Vous êtes sur la page 1sur 32

16/03/2020 Chapitre 09 - L'assembleur x86 | SUPINFO, École Supérieure d'Informatique

Accéder à Open-Campus
Contact @SUPINFO

ACCUEIL CURSUS COURS ADMISSIONS CAMPUS DOCUMENTATION ANCIENS ENTREPRISES OPEN CAMPUS PUBLICATIONS Naviguer sur la page

ACCUEIL CURSUS COURS ADMISSIONS CAMPUS DOCUMENTATION ANCIENS ENTREPRISES OPEN CAMPUS PUBLICATIONS

Chapitre 09 - L'assembleur x86


Précédent Computer Architecture

Cyril-Alexandre PACHON

Professeur Référent à SUPINFO International University

PLAN DU CHAPITRE

1 PLAN DU CHAPITRE PRESENTATION DU MICROPROCESSEUR 80X86

LES INSTRUCTIONS DE BASE EN ASSEMBLEUR 8086

Un CPU exécute des instructions qui sont la résultante des programmes écrits LES VARIABLES EN ASSEMBLEUR 8086
avec des langages de programmation. Ces instructions contenues dans la
mémoire composent le langage d’assemblage (assembleur). Pour qu’un LE SYSTEME VIDEO DU 8086

programme fonctionne, le CPU lit une part une les instructions. Donc pour les
LES INSTRUCTIONS DE SAUTS EN ASSEMBLEUR 8086
atteindre, les instructions sont rangées dans la mémoire via des adresses. Au
chargement d’un programme, le CPU dispose de l’adresse d’origine et contient LES PROCEDURES EN ASSEMBLEUR 8086
dans son Compteur Ordinal l’adresse de la future instruction à exécuter.
LES INSTRUCTIONS D’INTERRUPTIONS EN ASSEMBLEUR
Les instructions disposent de toutes les données pour que combinées entre
8086
elles et exécutées sur le CPU l’algorithme original traduit en langage de
programmation fonctionne. Les données des instructions se retrouveront soit LES PROGRAMMES EN ASSEMBLEUR 8086
dans les registres du CPU soit dans la mémoire centrale.
L’OUTIL EMU8086
Il existe 2 familles d’architecture de CPU, les CISC ( Complex Instruction Set
Computer ) et les RISC ( Reduced Instruction Set Computer ). Leurs différences L’ADRESSAGE
résident dans la construction des instructions. Un ensemble d’instructions est
appelé jeux d’instructions ou ISA ( Instruction Set Architecture ).

Le CISC dispose de jeux d’instructions pouvant effectuer plusieurs opérations, comme les opérations arithmétiques, les opérations
logiques, le chargement et la récupération de données en mémoire. Ils sont présents dans les x86, les pentiums, d’Intel, les 68xx de
Motorola.

Le RISC dispose d’instructions relativement petites, unitaires, codées sur les mêmes tailles de mot avec une exécution cadencée sur les
mêmes cycles d’horloge. Les instructions RISC sont possibles grâce à ses nombreux registres, caches (et aux mémoires) ne limitant pas la
taille des demandes. Les puces RISC sont conçues pour exécuter ces instructions très rapidement.

Pour rappel, un registre est un circuit ou composant de mémorisation interne au CPU et permet de stocker adresse et donnée utiles au
bon fonctionnement d’un programme en cours d’exécution. Dans un CPU, les registres sont toujours en nombre limités et pour un
meilleur contrôle chaque registre dispose d’un nom.

Ce chapitre va vous permettre d’appréhender la programmation en assembleur 8086. Il vous propose d’apprendre l’organisation interne
d’un processeur 80x86 16bits (base de toute une lignée de micro-processeur INTEL), de comprendre l’utilité des différents registres de
son CPU et de découvrir les bases du langage assembleur 8086 au travers de l’émulateur EMU 8086.

Toutes les parties de ce chapitre sont guidées par notre mode de programmation en 8086 car nous nous plaçons dans le cas où une
machine actuelle est trop difficile d’approche sans connaitre certains fondamentaux. Même si cela parait un peu vieillissant, il est de
bonne augure de concevoir les principes de base de façon simples. Cette étude permettra ensuite d’aborder dans d’autres cours des
parties plus actuelles voire futuristes de nos architectures. Il ne faut pas se méprendre sur les architectures actuelles, elles sont toutes
fondées sur des premiers principes, elles évoluent, elles se transforment mais les modèles eux restent toujours un fondement pour aller
utiliser, appréhender et comprendre les nouveautés. Nous allons donc décrire étapes par étapes les principes de la programmation en

https://www.supinfo.com/cours/1CPA/chapitres/09-assembleur-x86 1/32
16/03/2020 Chapitre 09 - L'assembleur x86 | SUPINFO, École Supérieure d'Informatique

assembleur 8086 tout en modélisant et étudiant la machine du même type dont elle dépend. L’émulateur 8086 sera notre outil de
Contact @SUPINFO
simulation lorsque nous en aurons besoin. L’émulateur sera bien sûr étudié pour mieux l’utiliser.
ACCUEIL CURSUS COURS ADMISSIONS CAMPUS DOCUMENTATION ANCIENS ENTREPRISES OPEN CAMPUS PUBLICATIONS Naviguer sur la page
L’assembleur est un langage de programmation proche du langage d’un ordinateur n’utilisant pas directement une notation
exclusivement faite avec des 0 et des 1. Il dispose de mnémoniques (de plus haut niveau) pour construire des programmes avec
structures de données et structures de traitements. L’assembleur dépend fortement du type de processeur. Donc il n’y a pas de langage
d’assembleur unique et chaque constructeur a son assembleur. Par conséquent, il est obligatoire de maitriser le fonctionnement d'un
processeur pour pouvoir aborder cette partie.

L'assembleur contrôle directement le CPU, il a une maîtrise du système et peut proposer des programmes rapides. Bien que les langages
de plus niveau comme le C, C++, C#, Python, … permettent de faire des programmes facilement, ils n'optimisent pas le code d'exécution.
L’impact est d’avoir des programmes plus volumineux pour faire la même demande.

Ce chapitre comporte principalement 9 parties sur la programmation assembleur :

1. les instructions de l’assembleur.


2. les variables. 3. le fonctionnement du système vidéo.
3. les instructions de programmation par ancres.
4. les procédures.
5. les ininterruptions.
6. la construction de programmes.
7. l’outil assembleur 8086.
8. les adressages mémoire.

2 PRESENTATION DU MICROPROCESSEUR 80X86

Le microprocesseur 80x86 se présente sous la forme d'un boîtier DIP ( Dual Inline Package ). En électronique un DIP est un boitier
contenant des circuits intégrés qui dispose de sorties pour se connecter à un environnement externe (de nouveau un circuit intégré). Il
est à noter que les DIP sont lié à un PCB ( Printed Circuit Board ) pour faciliter la manipulation tout en limitant les détériorations. Ainsi le
boitier peut s’insérer facilement sans risque. Par conséquent la PCB ( ou carte électronique ) est une plaque de soutènement de
composants permettant les liens entre les composants. Ce processeur a un bus d'adresses et un bus de données multiplexés (certaines
pattes transmettent à certains moments un bit d'adresse et à d'autres moments un bit de donnée). Il est organisé autour d’un bus
interne de données de 16 bits, il comporte:

16 broches pour transporter les données (AD 0 ... AD 15 ).

20 broches pour véhiculer les adresses (A 0 ... A 19 ). Il peut adresser 2 20 (= 1048576) positions mémoire différentes contenant
chacune 1 octet (8 bits) : la mémoire a au plus une capacité de 1 Mo.
de registres, 16 bits pour stocker des données.
de registres, 16 bits pour stocker des adresses (codées sur 20 bits).
de registres temporaires directement pour UAL.
un bloc pour former des adresses, 20 bits à partir de morceaux d’adresse codés sur 16 bits.

Figure 1.1. Représentations externe d’un 80x86

Un registre est un composant de mémoire interne au microprocesseur dont sa capacité est calibrée sur une taille des instructions. Ainsi
nous pouvons avoir des tailles de registres de 8 bits, 16 bits, 32 bits, 64 bits, … selon le modèle et la structure du micro-processeur. Le

https://www.supinfo.com/cours/1CPA/chapitres/09-assembleur-x86 2/32
16/03/2020 Chapitre 09 - L'assembleur x86 | SUPINFO, École Supérieure d'Informatique

rôle du registre est de stocker des adresses ou des résultats intermédiaires des calculs en cours. Les commandes de l'assembleur
Contact @SUPINFO
manipulent les registres. Pour les contrôler et les utiliser chaque registre dispose d’un nom.
ACCUEIL CURSUS COURS ADMISSIONS CAMPUS DOCUMENTATION ANCIENS ENTREPRISES OPEN CAMPUS PUBLICATIONS Naviguer sur la page
Comme tout CPU le 8086 dispose d'un certain nombre de type de registres:

les registres généraux destinés au traitement des valeurs. Ils permettent d’effectuer des additions, des multiplications, des calculs
logiques, nommés A ( Accumulateur ), B ( Base ), C ( Compteur ), D ( Donnée ).
les registres d'adressages (registres de segments, pointeurs et index) utilisés pour pointer, lire ou écrire un endroit en mémoire,
nommés D ( Donnée ), S ( Stack - Pile ), C ( Code ), E ( Extra ). L’IP ( Instruction Pointer ) sera aussi nommé CO ( Compteur Ordinal ).

Figure 1.2. Représentations interne d’un 80x86

les registres des états (Flags - Indicateurs) pour indiquer l'état du CPU. Ils donnent une indication sur le résultat de la dernière
instruction exécutée, par exemple ZF ( Zero Flag ) qui indique zéro, CF ( Carry Flag ) qui indique une retenue, NF ( Negative Flag ) ou SF
( Sign Flag ) qui indique si le résultat est négatif ou positif, OF ( Overflow Flag ) qui indique un dépassement de capacité de registre, PF
( Parity Flag ) qui indique si les 8 bits de poids fort sont constitué d’un nombre pair de 1 ….

Figure 1.3. Registres des états du 80x86

Les flags du registre d’état de la figure ci-dessus contiendront alors les valeurs mis à 0 ou 1 par le processeur (à la suite de l'exécution
d'une instruction) ou par le programmeur pour modifier le mode de fonctionnement du processeur.

La gestion des registres est faite avec des instructions processeurs. Ces instructions sont formées avec le code binaire des programmes à
exécuter. Il est possible de programmer le processeur avec des langages de plus bas niveau et pour rendre plus facile la manipulation, la
lecture et l’écriture de telles instructions binaires, le programmeur utilise des symboles (mots clés, ou mnémoniques) à la place de des
codes binaires et fait appel à l’assembleur. Les symboles en assembleur sont souvent la compression d'un mot ou d'une expression
réalisant une action. Par exemple MOV (MOVe), MUL (MULtiply), … . Les mnémoniques sont suivies de registres, de valeurs, … .

L’architecture du 80x86 est little-endian (le Motorola 68000 et le PowerPC sont par exemple big-endian). Par exemple pour l’entier
F1AB 16 en mémoire, il y a 2 possibilités :

le mode big-endian : D'abord l'octet F1 16 , puis l'octet AB 16 .


le mode little-endian : D'abord l'octet AB 16 , puis l'octet F1 16 .

https://www.supinfo.com/cours/1CPA/chapitres/09-assembleur-x86 3/32
16/03/2020 Chapitre 09 - L'assembleur x86 | SUPINFO, École Supérieure d'Informatique

Si nous manipulons des nombres codés sur 16 bits (1 mot mémoire), nous utilisons 4 registres généraux :
Contact @SUPINFO

AX, l‘Accumulateur, utilisé pour stocker les résultats de certains calculs arithmétiques et logiques.
ACCUEIL CURSUS COURS ADMISSIONS CAMPUS DOCUMENTATION ANCIENS ENTREPRISES OPEN CAMPUS PUBLICATIONS Naviguer sur la page
BX, la Base, utilisé comme registre de base pour des données dans le segment pointé par le registre de segment ES. Un segment
est un ensemble d’octets consécutifs dont un octet désigne le couple (numéro du segment, déplacement dans le segment).
CX, le Compteur, utilisé pour les boucles.
DX, le registre de Données, contient l'adresse des ports d'entrée/sortie (pour les instructions IN et OUT) et sert également
d'extension à AX pour manipuler les données sur 32 bits.

Si nous manipulons des nombres codés sur 8 bits (1 octet), nous utilisons les 4 registres généraux en mode 8 bits pour en produire 8
registres AH, AL, BH, BL, CH, CL, DH et DL avec comme convention, H est mis pour "High" et L pour "Low" :

AH contient l'octet de poids fort du registre AX.


BH contient l'octet de poids fort du registre BX.
….
AL contient l'octet de poids faible du registre AX.
BL contient l'octet de poids faible du registre BX.
….

Figure 1.4. Registres généraux en mode 16bits et 8 bits

Les 2 registres d'index, notés SI ( Source Index ) et DI ( Destination Index ), sont utilisés pour indexer les éléments d'un tableau. Dans les
instructions de mouvements de chaînes d'octets, ils sont utilisés simultanément :

SI indexe les caractères de la chaîne émettrice.


DI indexe les caractères de la chaîne réceptrice.

Une instruction dans le CPU est composée de plusieurs segments. Un segment qui désigne le code du programme, un segment qui
désigne les données, un segment qui désigne l’organisation des appels, ….. Une instruction contient donc tous ses segments, mais sous
forme d’adresse pointant vers la mémoire. Pour accéder à sa mémoire centrale, le 80x86 dispose de registres de segment suivants:

Figure 1.5. Pointeur de zone pour un programme en assembleur 8086

https://www.supinfo.com/cours/1CPA/chapitres/09-assembleur-x86 4/32
16/03/2020 Chapitre 09 - L'assembleur x86 | SUPINFO, École Supérieure d'Informatique

Contact @SUPINFO

ACCUEIL
( Code Segment
CS CURSUS ) pointe sur la base du segment qui contient le code (les instructions que doit exécuter le processeur).
COURS ADMISSIONS CAMPUS DOCUMENTATION ANCIENS ENTREPRISES OPEN CAMPUS PUBLICATIONS Naviguer sur la page
DS ( Data Segment ) pointe sur la base du segment contenant les données (variables, tableaux ...).
SS ( Stack Segment ) pointe sur la base du segment qui contient la pile gérée par les registres SP et BP.
ES ( Extra Segment ) pointe sur la base d'un segment supplémentaire qui est généralement utilisé pour compléter le segment de
données.

Ces segments sont situés selon la place disponible dans la mémoire. Parfois, ces segments peuvent se chevaucher partiellement. Les
adresses des segments sont données et gérées par le système d’exploitation lors du mécanisme de chargement du programme à
exécuter. Comme les adresses sont ensuite contrôlées de façon automatique, normalement il n’y a pas de risque de confusions d’accès
(des systèmes de gestion d’erreurs peuvent se mettre en place comme les blue Sreen). Par contre, les déplacements sont liés aux
instructions contenues dans le programme en se base sur une adresse d’origine.

La pile est une zone de mémoire qui permet de conserver de manière temporaire des données (par exemple, l’état des registres lors d’un
appel de procédure). Nous utilisons 2 registres pointeurs :

SP ( Stack Pointer ) pointe sur le sommet de la pile et se met à jour automatiquement par les instructions d'empilement et de
dépilement.
BP ( Base Pointer ) pointe la base de la région de la pile contenant les données accessibles (variables locales, paramètres,...) à
l'intérieur d'une procédure. Il doit être mis à jour par le programmeur.

La pile n'est pas gérée avec des registres, elle utilise la mémoire (RAM). Dans cette pile, les données sont naturellement stables et seuls
les pointeurs SP et BP sont utilisés pour atteindre les données. Cette pile est de type LIFO et elle est manipulée par :

PUSH pour empiler une valeur de 16 bits (le pointeur SP est décrémenté automatiquement de 2).
POP pour dépiler une valeur de 16 bits (SP est incrémenté automatiquement de 2).

Le bus d’adresse de la mémoire réelle est de 20 bits. Or le 80x86 n’a pas de registre de 20 bits mais que de 16 bits. Un registre de 16 bits
référence 64Ko de mémoire, soit 2 16 = 65 536. Pour répondre à cette problématique le 80x86 en mode réel combine un des neuf
registres généraux avec l'un des quatre registres de segments pour former une adresse de 20 bits.

Le registre IP ( Instruction pointer ) est appelé pointeur d'instruction ou compteur ordinal. La valeur contenue dans ce registre aiguille
instruction par instruction les déplacements le micro-processeur. Il propose toujours la prochaine adresse de l’instruction à exécuter par
le micro-processeur. Le registre IP est constamment modifié après chaque fin instruction pour qu'il puisse pointer sur l'instruction
suivante. Ce registre permet de pointer une case mémoire dans le segment de code afin que le 80x86 puisse charger la prochaine
instruction à exécuter.

À chaque type d'accès en mémoire, il faut faire correspondre un registre de segment et parfois un registre général, par exemple :

CS et IP sont combinés pour accéder à la prochaine instruction à exécuter sous la forme CS:IP.
SS et SP sont combinés en SS:SP pour toutes les opérations concernant la pile.

II est possible d'utiliser un registre de segment autre que celui utilisé par défaut en le spécifiant explicitement. Mais les valeurs de CS, DS
et SS sont produites par le système d’exploitation dès le lancement du programme. Ces valeurs de segments étant implicites, il sera
possible de les utiliser juste en spécifiant les offset de déplacements.

Pour adresser 1 méga-octet, il faut 4 bits, en plus des 16 bits d'un registre général. Cette combinaison est obtenue en décalant le registre
de segment de 4 bits et en ajoutant le résultat au contenu du registre général pour obtenir l'adresse sur 20 bits.

Le résultat est appelé EA ( Effective Address ). L'EA est placée sur le bus d'adresses afin de pouvoir accéder à l'emplacement mémoire
correspondant. L’EA est constituée de deux parties, le registre de segment définissant une zone mémoire de 64Ko, et le registre général
spécifiant un déplacement à partir de l'origine de ce segment de 64Ko (c'est-à-dire une adresse sur 16 bits à l'intérieur de ce segment).

L’EA est exprimée en donnant le registre segment et le registre général séparés par deux points par exemple: DS:SI. Le registre DS est le
segment de 64Ko et SI contient le déplacement dans ce segment. Si nous avons par exemple 1A8B:0010, l'adresse du segment est 1A8B
et le déplacement dans le segment est 0010 en hexadécimal. Pour obtenir l’EA il faut faire : 1A8B * 10 16 + 10 = 1A8C0.

3 LES INSTRUCTIONS DE BASE EN ASSEMBLEUR 8086

3.1 Le codage des nombres

Les nombres sont codés sur 1 ou 2 octets selon la taille de la valeur est l’utilisation des registres (une extension est possible pour 4 octet,
mais les opérations seront spécifiques). Il y a 4 types de codages des nombres aussi bien en base 2, 8, 10, 16, …. :

1. entiers positifs (1110b, 26o, 10, FFh).


2. entiers entier négatifs (-1110b, -26o, -10, -FFh).

https://www.supinfo.com/cours/1CPA/chapitres/09-assembleur-x86 5/32
16/03/2020 Chapitre 09 - L'assembleur x86 | SUPINFO, École Supérieure d'Informatique

3. décimaux compactés (codage binaire).


Contact @SUPINFO
4. décimaux non compactés (nombre à virgule).
ACCUEIL CURSUS COURS ADMISSIONS CAMPUS DOCUMENTATION ANCIENS ENTREPRISES OPEN CAMPUS PUBLICATIONS Naviguer sur la page
L’algorithme de codage des négatifs est le complément à 2. Les normes de stockage des décimaux sont standardisées par la IEEE745.
Une valeur numérique commence toujours par un chiffre, c’est ainsi que si l’émulateur refuse d’exécuter une valeur hexadécimale, c’est
qu’il ne comprend pas qu’il s’agit d’un chiffre. Par conséquent, il faudra ajouter en tête de la valeur 0x ou simplement 0 pour indiquer
une constante.

3.2 Les instructions

Un microprocesseur exécute un jeu d'instructions relatif au programme créé par le concepteur. Une instruction réalise une action simple
sur le microprocesseur, comme "récupérer une nombre en mémoire", "additionner deux nombres et placer le résultat en mémoire".
L'assembleur aura pour rôle de convertir le fichier source contenant les instructions; en mnémoniques (indication sous forme de lettre
de l’opération à effectuer), en actions sur les registres et mémoire. Le fichier exécutable produit contient les codes binaires de chacune
des instructions, compréhensible uniquement par le microprocesseur associé. L'assembleur est donc qu’une traduction d’un fichier
source éditer en langage de haut niveau vers un langage binaire (de bas niveau).

Le codage d’une instruction en langage de programmation est constitué d’un code-opérateur (CodeOp) ou mnémonique (codé sur 1 ou 2
octets) suivi d’opérandes (valeur immédiate, registre, adresse). Par exemple, pour additionner 60 10 avec 15 10 , le code en assembleur
sera le suivant:

MOV AX, 60
ADD AX, 15

Ces instructions se traduisent en :

1. placer la valeur immédiate 60 dans le registre AX (MOV Ax, 60).

2. additionner le contenu de AX avec 15 et replacer le résultat dans AX (ADD AX, 15).

Ces instructions sont codées en hexadécimal, car il y a une correspondance numérique entre les mnémoniques, registres et valeurs,
nous obtenons :

B83C00 16

050F00 16

Et l’algorithme de codage avec l’hexadécimal produit en binaire :

101110000011110000000000 2

000001010000111100000000 2

En lisant les valeurs binaires, les seules valables pour le microprocesseur, l’assembleur en utilisant les noms des registres, les
mnémoniques,… devient bien un langage de programmation, et même de haut niveau dû à sa lisibilité par rapport au binaire.

Pour des raisons de souplesse, d’explication et de manipulation une instruction sera constituée de l’opérateur (ADD, MOV,….) suivi des
adressages (données participant à l’opération). C’est ainsi nous aurons besoin d’avoir pour les adressages de nommer et manipuler:

registre (direct par A, B, C, D, S).


registre ou variable (direct par A, B, C, D, S ou définit par DB ou DW).
variable (définit par DB ou DW).
constante (définit pas EQU).
label (nom donné comme ancre de programmation).

3.3 Opérations logiques

Le 8086 permet d’effectuer des opérations binaires classiques grâce au mnémoniques AND, OR, NOT et XOR. Ces opérateurs peuvent
être utilisés avec :

AND/OR/XOR register ou variable, registre


AND/OR/XOR register, register ou variable
AND/OR/XOR register ou variable, constante
AND/OR/XOR register ou variable, nombre
NOT registre ou variable

https://www.supinfo.com/cours/1CPA/chapitres/09-assembleur-x86 6/32
16/03/2020 Chapitre 09 - L'assembleur x86 | SUPINFO, École Supérieure d'Informatique

Example 1.1. Des opérations avec opérateurs logiques binaires classiques


Contact @SUPINFO

ACCUEIL CURSUS COURS ADMISSIONS CAMPUS DOCUMENTATION ANCIENS ENTREPRISES OPEN CAMPUS PUBLICATIONS Naviguer sur la page
MOV AL, 01100001b
AND AL, 11011111b --> Nous obtenons 01000001b
OR AL, 01110110b --> Nous obtenons 01110111b
NOT AL --> Nous obtenons 10001000b
XOR AL, 01010101b --> Nous obtenons 11011101b
XOR BX, BX --> Nous obtenons 00000000b

Le 8086 permet d’effectuer des opérations de décalage sur des nombres signés ou non signés. Les bits qui sont expulsés sont stockés
dans le bit CF :

SHL ( SHift Left ) et SAL ( Shift Arithmetic Left ).


SHR ( SHift Right ) et SAR ( Shift Arithmetic Right ).

La différence entre les 2 types de décalage est que dans la seconde version le bit de signe n’est pas concerné par ce décalage. Cette
opération est plus rapide à exécuter que l’opération de multiplication ou de division par 2. Le nombre de bits de décalage est indiqué
dans la seconde opérande.

Example 1.2. Des opérations avec opérateurs logiques binaires de décalage

MOV AL, 11110000b


SHL AL, 1 --> Nous obtenons 11100000b
SAL AL, 1 --> Nous obtenons 11000000b
SAR AL, 1 --> Nous obtenons 10100000b
SHR AL, 1 --> Nous obtenons 01010000b

Le 8086 permet de réaliser des opérations de rotation sur des nombres signés ou non signés. Les bits expulsés sont replacés dans les
trous formés par ce décalage :

ROL ( Rotate Left ) et RCL ( Rotate Throw Carry Left ).


ROR ( Rotate Right ) et RCR ( Rotate Throw Carry Right ).

La différence entre les 2 types de décalage est que dans la seconde version le bit CF est utilisé en plus des bits à modifier (lors d’un
mouvement, le trou est rempli avec une copie du bit CF et l’autre bit, qui est expulsé, est placé dans CF). Le nombre de bits de décalage
est indiqué dans la seconde opérande.

Example 1.3. Des opérations avec opérateurs logiques binaires de rotation

MOV AL, 11110000b


ROL AL, 1 --> Nous obtenons 11100001b ; nous supposons CF=0
RCL AL, 1 --> Nous obtenons 11000010b et CF = 1
RCR AL, 1 --> Nous obtenons 11100001b et CF = 0
ROR AL, 1 --> Nous obtenons 11110000b

3.4 Opérations arithmétiques

Comme pour tous calculateurs et microprocesseurs les unités de traitements arithmétiques font les opérations +, -, * et /. Pour les
utiliser et le décrire, nous passons toujours par des symboles. Par contre pour effectuer des calculs dits non de bases, il faudra faire des
programmes et enchainer les calculs, décalages et rotations.

Les mnémoniques ADD ( ADDition ) et SUB ( SUBtraction ) permettent d’effectuer des additions et des soustractions. Ils sont construit par :

ADD registre, registre ou variable


ADD registre ou variable, registre
ADD registre ou variable, constante
SUB registre, registre ou variable
SUB registre ou variable, registre
SUB registre ou variable, constante

https://www.supinfo.com/cours/1CPA/chapitres/09-assembleur-x86 7/32
16/03/2020 Chapitre 09 - L'assembleur x86 | SUPINFO, École Supérieure d'Informatique

Example 1.4. Addition et soustraction en assembleur 8086 Contact @SUPINFO

ACCUEIL CURSUS COURS ADMISSIONS CAMPUS DOCUMENTATION ANCIENS ENTREPRISES OPEN CAMPUS PUBLICATIONS Naviguer sur la page
ADD AX, BX ; effectue l’opération AX <-- AX + BX
SUB AX, BX ; effectue l’opération AX <-- AX – BX

Si une addition ou une soustraction sont codées sur 16 bits, alors leurs résultats seront codés sur au plus 16 + 1 bits soit 16 bits de
résultat + 1 bit de retenue (le bit CF). Les opérations ADD et SUB sont effectuées sans tenir compte de l’état initial du bit CF du registre
d’état mais l’état de ce bit peut être modifié à l’issue de l’opération.

Le 8086 propose 2 instructions INC et DEC pour incrémenter ou de décrémenter :

INC registre ou variable


DEC registre ou variable

Par exemple :

INC AX incrémente la valeur stockée dans AX. INC AX donne le même résultat que ADD AX, 1 mais le premier mnémonique
correspond à un codeop de 1 octet alors que le codeop correspondant au second mnémonique en occupe 3.
DEC BX décrémente la valeur stockée dans BX. DEC BX donne le même résultat que SUB BX, 1 mais le premier mnémonique
correspond à un codeop de 1 octet alors que le codeop correspondant au second mnémonique en occupe 3.

Pour effectuer des additions sur 32 bits avec des registres limités à 16 bits, nous devons scinder les nombres en 2 parties :

1 registre pour stocker les 16 bits de poids fort.


1 registre pour stocker les 16 bits de poids faible. Nous effectuons d’abord l’addition entre les 16 bits de poids faible puis l’addition
entre les 16 bits de poids fort en utilisant le bit CF pour propager la retenue entre les 2 blocs de 16 bits.

Figure 1.6. Propagation d’une retenue pour un mot de 32 bits en ASM

Pour demander au processeur d’effectuer des additions qui tiennent compte du bit CF, nous devons utiliser un nouveau mnémonique :
ADC ( ADdition with Carry ).

Il n’existe pas de mnémonique SUBC mais un mnémonique appelé SBB ( SuBtract with Borrow ) qui effectue le même type d’opération
mais en sens inverse.

Comme les opérations ADC et SBB modifient l’état du bit CF, il sert à effectuer des opérations sur 48 bits, 64 bits … en stockant les
résultats intermédiaires en mémoire, l’opération se fera par bloc de 16 bits.

Le mnémonique MUL ( MULtiply ) permet les multiplications, mais son mode de fonctionnement est très différent par rapport à celui de
l'addition et la soustraction.

MUL registre ou variable.

La multiplication MUL avec deux données de 8 bits donne comme résultat une valeur codée sur 16 bits, donc de façon directe les valeurs
données ne peuvent pas dépasser les bits de poids faibles. Si les valeurs dépassent les 8 bits, il faut alors utiliser plusieurs registres.
Pour multiplier un nombre N par un nombre M, nous devons d'abord copier le nombre N dans le registre AL (ou AX) puis invoquer
l’instruction MUL M :

si l’opérande est un octet, nous calculons AL * opérande et le résultat est stocké dans AX.
si l’opérande est un mot, nous calculons AX * opérande et le résultat est stocké dans les registres DX et AX (DX contenant la partie
de poids fort).

Le 8086 propose un autre mnémonique pour effectuer les multiplications entre 2 nombres signés. Le mnémonique IMUL est utilisé de la
même manière que le mnémonique MUL à la différence que les opérandes sont considérés comme des nombres signés (codés en
complément à 2) et que le résultat est un nombre signé.

Le mnémonique de la division euclidienne est DIV et son mode de fonctionnement est voisin de celui de MUL.

https://www.supinfo.com/cours/1CPA/chapitres/09-assembleur-x86 8/32
16/03/2020 Chapitre 09 - L'assembleur x86 | SUPINFO, École Supérieure d'Informatique

Pour diviser un nombre N par un nombre M, nous devons d'abord copier le nombre N dans le registre AX (ou AX et DX) puis invoquer
Contact @SUPINFO
l’instruction DIV M :
ACCUEIL CURSUS COURS ADMISSIONS CAMPUS DOCUMENTATION ANCIENS ENTREPRISES OPEN CAMPUS PUBLICATIONS Naviguer sur la page
si l’opérande est un octet, nous calculons AX / opérande : le quotient est stocké dans AL et le reste dans AH.
dans le cas d’un mot, nous calculons (AX DX) / opérande : le quotient est stocké dans AX et le reste dans DX.

Le 8086 propose un autre mnémonique pour effectuer les divisions euclidiennes entre 2 nombres signés. Le mnémonique IDIV est utilisé
de la même manière que le mnémonique DIV. Les différences sont que les opérandes sont considérées comme des nombres signés
(codés en complément à 2) et que le résultat est un nombre signé.

3.5 Utilisations des contrôles

Le 8086 offre 3 instructions pour modifier directement l’état du bit CF :

STC ( SeT Carry flag ) permet de mettre CF à 1.


CLC ( CLear Carry flag ) permet de mettre CF à 0.
CMC ( CoMplement Carry flag ) permet d’inverser l’état du bit CF.

Le 8086 offre 4 instructions pour modifier directement l’état des bits DF (direction) et IF (interruptions externes) :

STD ( SeT Direction flag ) permet de mettre DF à 1.


CLD ( CLear Direction flag ) permet de mettre DF à 0.
STI ( SeT Interrupt flag ) permet de mettre IF à 1.
CLI ( CLear Interrupt flag ) permet de mettre IF à 0.

Les mnémoniques STI et CLI sont utiles pour implanter au niveau assembleur des procédures qui ne peuvent pas être interrompues par
des événements externes.

Les mnémoniques STD et CLD sont utiles pour aiguiller le sens de manipulation des chaines d’octets. Si le flag DF est à 0, le traitement
est de gauche à droite, si DF est à 1 le traitement va de droite à gauche.

4 LES VARIABLES EN ASSEMBLEUR 8086

Comme pour tous les langages, avant d’utiliser une variable, il faut initialement la déclarer. Les variables sont considérées comme des
emplacements mémoire qui peuvent être manipulés par l’intermédiaire de leur adresse ou de leur nom.

Le nom d’une variable peut être une combinaison de chiffres, de lettres et du caractère « _ », mais il doit respecter les contraintes
suivantes :

1. ne jamais commencer par un chiffre.


2. ne pas correspondre à un mot clé du langage Assembleur.

Lorsque l’association entre le nom et la variable est créée, ce nom peut être utilisé pour désigner l’emplacement mémoire contenant
l’information. L’assembleur traduit le nom en une adresse lors du processus d’assemblage.

4.1 Simples variables et numériques

L'association entre le nom et l'adresse s'effectue en utilisant les instructions DB ( Define Byte – 1 octet pour 8086) ou DW ( Define Word –
2 octets pour 8086) selon que la variable contient des octets ou des mots.

La valeur associée à la variable peut être un nombre (hexadécimal, décimal ou binaire) ou le symbole ? (si la variable n’est pas initialisée),
par exemple :

var1 DB 50h
var2 DB ?
var3 DW 1110h

Il peut être intéressant de connaître l’adresse d’une variable pour utiliser cette dernière comme argument des interruptions logicielles.
Celle-ci se décompose en 2 parties :

1. l’adresse du segment, obtenue par l’opérateur SEG.


2. le déplacement à l’intérieur du segment, accessible grâce à l’opérateur OFFSET ou l’instruction LEA ( Load Effective Address ).
L’instruction LEA CX, var1 sera traduite en MOV CX, 00100h (avec par exemple 00100h étant la valeur du déplacement pour la
variable var1).

https://www.supinfo.com/cours/1CPA/chapitres/09-assembleur-x86 9/32
16/03/2020 Chapitre 09 - L'assembleur x86 | SUPINFO, École Supérieure d'Informatique

Lors du processus d’assemblage, des transformations sont opérées au niveau du code :


Contact @SUPINFO

1. SEG nom remplacé par le nom du registre associé au segment contenant la donnée.
ACCUEIL CURSUS COURS ADMISSIONS CAMPUS DOCUMENTATION ANCIENS ENTREPRISES OPEN CAMPUS PUBLICATIONS Naviguer sur la page
2. OFFSET nom remplacé par la valeur du déplacement.

var1 DB 50h

MOV AX, SEG var1


MOV BX, OFFSET var1

L’exemple ci-dessus sera interprété par, un placement de pointer suivi d’un déplacement (valeur dépendant du nombre d’instruction
contenu dans le fichier) :

MOV AX, CS
MOV BX, 00100h

Une constante numérique est définie grâce à la directive EQU qui indique à l’assembleur que le nom de cette constante doit être
remplacée par sa valeur au moment de la création de l’exécutable.

var1 EQU 50h

MOV AX, var1

L’exemple ci-dessus, définit une constante nommée var1 dont sa valeur est 50h et sera interprété par :

MOV AX, 00050h

Il faut noter la différence entre une constante initialisée par EQU et une variable initialisée par DB ou DW. EQU construit une constante
dont la valeur est immédiate (et normalement invariante) alors que les autres déclarations construisent des variables dont les valeurs se
situent aux adresses de stockage des valeurs. C’est donc pour cela que DB et DS pourront ne pas avoir de valeurs initialement données
et pourront récupérer des valeurs au cours de l’exécution du programme.

4.2 Tableaux

Un tableau peut être vu comme une liste de variables qui sont associées à un même nom. La création d’un tel tableau s’effectue alors de
la manière suivante :

tab DB 01h, 02h, 03h

Il est alors possible d’accéder à une case précise du tableau en utilisant un opérateur d’indexation : nous écrivons le nom du tableau
suivi du numéro de la case placé entre crochet (les cases étant numérotées de 0 à N-1 pour un tableau comportant N éléments) :

MOV AX, tab[1]

Si un tableau est construit en répétant une ou plusieurs valeurs, il peut être utile d’utiliser l’opérateur DUP, par exemple :

tab DB 5 DUP (1,2)

L’opérateur DUP nécessite 2 informations :

le nombre de répétition (un entier placé après DB).


la liste des variables à répéter, que nous plaçons entre parenthèses.

https://www.supinfo.com/cours/1CPA/chapitres/09-assembleur-x86 10/32
16/03/2020 Chapitre 09 - L'assembleur x86 | SUPINFO, École Supérieure d'Informatique

4.3 Chaines de caractères Contact @SUPINFO

ACCUEIL CURSUS COURS ADMISSIONS CAMPUS DOCUMENTATION ANCIENS ENTREPRISES OPEN CAMPUS PUBLICATIONS Naviguer sur la page
Une chaîne de caractères peut être vue comme un tableau contenant une suite de code ASCII séparés par une virgule (correspondant
chacun à une lettre). Dans tous les cas, et pour faciliter les parcours et les recherches, les chaines de caractères seront terminées par le
symbole $ (pour marquer la fin de la chaîne de caractères).

var4 DB 72, 69, 76, 76, 111, 36

Cette écriture est fastidieuse car il faut connaître le code ASCII de chaque caractère. Nous pouvons opter pour une séquence dissociée
de caractères notés chacun entre symboles ' ' et séparés par une virgule.

var5 DB 'H' , 'E' , 'L' , 'L' , 'O' , '$'

Ou pour une séquence concaténée de caractères avec un symbole ' en début et en fin.

var6 DB 'HELLO$'

5 LE SYSTEME VIDEO DU 8086

5.1 Le moniteur

La présentation reste adapter à notre mode de programmation assembleur. Nous allons rester dans des modes simples, qui permettent
de mieux appréhender l’apprentissage voulu ici. Pour décrire le balayage et la formation d’une image couleur, le moniteur reçoit de la
part du contrôleur d'écran des signaux analogiques correspondant à l'image à afficher :

certains fils transportent les 3 informations à destination des canons électrons.


d'autres transportent des signaux de synchronisation permettant de piloter le dispositif électronique de balayage du moniteur.

En première définition, le moniteur couleur fonctionne de la manière suivante :

1. le moniteur reçoit un premier signal de synchronisation qui ordonne au moniteur de baisser très fortement l'intensité des canons
(de manière à faire disparaître le spot) puis à modifier l'alimentation des bobines de déviation de manière à placer le spot dans le
coin supérieur gauche de l'écran (côté spectateur).
2. le moniteur reçoit un deuxième signal de synchronisation qui lui indique de prendre en compte les signaux de couleur à
destination des canons (il s’agit d’un spot).
3. les fils transportant les signaux de couleur et le signal de balayage vertical sont envoyés de manière synchrone vers le moniteur.
Le spot se déplace de la gauche vers la droite et les luminophores de la ligne sont bombardés chacun leur tour avec une intensité
dépendant de la couleur à produire.
4. le moniteur reçoit un signal lui indiquant d'éteindre le spot et de le ramener très rapidement vers la gauche de l'écran, un cran
plus bas pour former la ligne suivante.

Les étapes 3 et 4 sont répétées jusqu'à former l'image complète. Lorsque l'image est totalement formée, nous retournons à la première
étape.

5.2 Le contrôleur d’écran

Le contrôleur d'écran est souvent désigné sous le terme de carte vidéo ou encore de CRTC ( Cathode Ray Tube Controler ). Il existe de très
nombreuses cartes vidéo capables de gérer les dessins en 3D, les textures ... Cependant, comme nous nous intéressons au processeur
80x86, nous allons plutôt décrire une carte plus ancienne, la carte CGA ( Color Graphic Adaptator ), dont le fonctionnement sera plus aisé
à comprendre. Construite autour d'un circuit appelée le CRTC 6845 de Motorola. Cette carte peut fonctionner selon différents modes
texte:

40 x 25 caractères en monochrome.
40 x 25 caractères en 16 couleurs.
80 x 25 caractères en monochrome.
80 x 25 caractères en 16 couleurs. Cette carte peut fonctionner selon différents modes graphiques:

https://www.supinfo.com/cours/1CPA/chapitres/09-assembleur-x86 11/32
16/03/2020 Chapitre 09 - L'assembleur x86 | SUPINFO, École Supérieure d'Informatique

320 x 200 pixels en monochrome.


Contact @SUPINFO
320 x 200 pixels en 4 couleurs.
640CURSUS
ACCUEIL x 200 COURS
pixels ADMISSIONS
en 2 couleurs.
CAMPUS DOCUMENTATION ANCIENS ENTREPRISES OPEN CAMPUS PUBLICATIONS Naviguer sur la page

La carte CGA dispose d'une palette de 16 couleurs d’où sont tirées 2 sous-palettes utilisées pour le mode 320x200 en 4 couleurs:

sous-palette n°1 : "couleur de fond choisie", Turquoise, Violet, Blanc.


sous-palette n°2 : "couleur de fond choisie", Vert, Rouge, Jaune.

Table 1.1. Palette de 16 couleurs pour CGA

Décimal Hexadécimale Binaire Nom de la couleur


0 00h 0000 Noir

1 01h 0001 Bleu


2 02h 0010 Vert

3 03h 0011 Bleu de cobalt


4 04h 0100 Rouge

5 05h 0101 Violet


6 06h 0110 Marron

7 07h 0111 Gris clair


8 08h 1000 Gris sombre

9 09h 1001 Bleu clair


10 0Ah 1010 Vert clair

11 0Bh 1011 Bleu de cobalt clair


12 0Ch 1100 Rouge clair

13 0Dh 1101 Violet clair


14 0Eh 1110 Jaune

15 0Fh 1111 Blanc

La carte CGA dispose de registres internes du CRTC 6845 suffisants pour les anciennes cartes graphiques telles que la carte MDA
( Monochrome Display Adaptator ) qui équipait l'IBM PC de 1981. La carte CGA ayant des possibilités supplémentaires, d'autres registres
sont additionnés, comme par exemple :

un registre de sélection de mode.


un registre de sélection de la couleur.

Le registre de sélection de mode est sur 1 octet. Il va permettre de distinguer plusieurs modes tels que :

Table 1.2. Registre de sélection de mode

Contrôleur de mode Numéro du bit dans l’octet

02 = 40 * 25
A chage de caractères bit 0
12 = 80 * 25

02 = mode texte
Mode vidéo bit 1
12 = mode graphique

02 = sortir
Signal de couleur bit 2
12 = inhiber

02 = non
Production d'un signal bit 3
12 = oui

Mode graphique bit 4 12 = 640 * 200

02 = couleur de fond clair


E et d'a chage bit 5
12 = clignotant

Le registre de sélection de couleur est sur 1 octet. Il va permettre de distinguer plusieurs couleurs tels que :

Table 1.3. Registre de sélection de couleur

Contrôleur de couleur Numéro du bit dans l’octet


mode texte 40 * 25
Couleur de fond bit 3
mode graphique 320 * 25
Couleur de fond intense bit 4 mode texte

Palette de couleur bit 5 mode graphique 320 * 200

5.3 La mémoire vidéo

Pour le système d'affichage, il existe la mémoire vidéo. Elle est accédée à la fois par le processeur (le plus souvent en écriture) et par le
Motorola 6845 qui constitue le cœur de la carte vidéo CGA.

Cette zone de mémoire a une capacité de 16 Ko et commence à l'adresse B800:0000. Les 16 Ko correspondent à 16 * 1024 octets, soit
16384 emplacements qui sont organisés de différentes manières selon le mode vidéo choisi. Dans cette présentation, nous allons nous

https://www.supinfo.com/cours/1CPA/chapitres/09-assembleur-x86 12/32
16/03/2020 Chapitre 09 - L'assembleur x86 | SUPINFO, École Supérieure d'Informatique

limitons au mode texte, plus facile à appréhender. En mode texte, un caractère est codé par 2 octets :
Contact @SUPINFO

le premier octet correspond simplement au code ASCII du caractère à afficher.


ACCUEIL CURSUS COURS ADMISSIONS CAMPUS DOCUMENTATION ANCIENS ENTREPRISES OPEN CAMPUS PUBLICATIONS Naviguer sur la page
le second octet permet de coder les attributs de ce caractère (la couleur de fond, la couleur de forme, et son clignotement).

Le mode texte en 80*25 nécessite 80*25*2 octets soit 4000 octets. Comme la mémoire vidéo a une capacité de 16 Ko, nous pouvons
mettre en place 4 pages :

la première page commence généralement à l'adresse B800:0000.


la deuxième à l'adresse B800:1000.
la troisième en B800:2000.
la quatrième en B800:3000.

L'intérêt de ce système de pagination est de pouvoir construire une page (que le processeur accède en écriture) pendant qu'une autre
page est affichée (le Motorola 6845 accède en lecture à une autre zone mémoire). Cela permet une plus grande fluidité au niveau de
l'affichage. Lorsque la page est prête, il suffit de modifier les registres 0Ch 0Dh du Motorola 6845 pour qu'il affiche la bonne page. Pour
déterminer la valeur du déplacement (offset) à l'intérieur d'une page, nous pouvons appliquer la formule : offset (colonne, ligne) = ligne *
160 + colonne * 2.

Après cette longue description, nous allons enfin afficher des caractères à l'écran. Pour commencer, nous allons d'abord afficher le
message «Bonjour,monde!!!» en écrivant les lettres dans les bonnes cases de la mémoire vidéo grâce à l'instruction MOV.

Figure 1.7. Programme et émulation d’affichage en ASM

Figure 1.8. : Programme et exécution de lettres de couleur en ASM

Figure 1.9. Programme et exécution de lettres avec fond en couleur en ASM

https://www.supinfo.com/cours/1CPA/chapitres/09-assembleur-x86 13/32
16/03/2020 Chapitre 09 - L'assembleur x86 | SUPINFO, École Supérieure d'Informatique

Contact @SUPINFO

ACCUEIL CURSUS COURS ADMISSIONS CAMPUS DOCUMENTATION ANCIENS ENTREPRISES OPEN CAMPUS PUBLICATIONS Naviguer sur la page

Figure 1.10. Programme et exécution de lettres en couleur et fond en couleur en ASM

Les différents affichages ont été faits avec une vision interne de l’architecture. Nous verrons dans la suite qu’il est possible de faire
intervenir des fonctions prédéfinies (notion d’interruptions) pour faire des affichages. Pour cela il faut introduire les notions de
navigation dans le code et ensuite nous construirons les interruptions.

6 LES INSTRUCTIONS DE SAUTS EN ASSEMBLEUR 8086

6.1 Les étiquettes

Les étiquettes (nommées aussi labels) permettent de spécifier au programme à quel endroit continuer une exécution. Il s’agit d’une
ancre de programmation, comme un point d’entrée pour commencer des instructions. Pour accéder à une étiquette, il est possible
d’utiliser un mnémonique de contrôle du flot d'instructions : JMP (pour jump). Nous parlons ainsi de programmation par Go To non
conditionnelle. Le branchement inconditionnel consiste simplement à sauter d'une position dans le code à une autre position pour
continuer l'exécution. Ce type de branchement est opposé aux branchements conditionnels qui réalisent des sauts en fonction des tests
effectués sur les bits du registre d'état. Le saut inconditionnel est JMP suivi d'un nom de l'étiquette (ou d'un nombre représentant
l'adresse de destination codée sur 4 octets mais ce n'est pas conseillé). Pour que les instructions s’exécutent, l’étiquette atteinte est
convertie en une adresse au moment de l'assemblage des instructions de saut.

Pour ajouter une étiquette dans le programme assembleur, il suffit de déclarer un nom (qui ne commence pas par un chiffre) suivi des 2
points ( : ).

Par exemple :

https://www.supinfo.com/cours/1CPA/chapitres/09-assembleur-x86 14/32
16/03/2020 Chapitre 09 - L'assembleur x86 | SUPINFO, École Supérieure d'Informatique

Contact @SUPINFO
etiquette1: MOV AX, BX
JMP etiquette1
ACCUEIL CURSUS COURS ADMISSIONS CAMPUS DOCUMENTATION ANCIENS ENTREPRISES OPEN CAMPUS PUBLICATIONS Naviguer sur la page

La partie du programme ci-dessus provoque une boucle entre l’instruction JMP etiquette1 et l’ancre etiquette1. Lors de l’exécution de
l’instruction le JMP décodée instruit le saut vers l’étiquette1. Pour cet exemple comme le programme reste une séquence vers JMP, il y a
une boucle de créée.

6.2 Les conditionnelles

A l'instar de l'instruction JMP, les instructions de branchement conditionnel s'utilisent avec un label. Elles doivent être placées juste après
l'instruction (CMP, DEC, INC ...) qui modifient l'état du registre d'état sinon les autres mnémoniques placées entre cette instruction et le
branchement conditionnel pourraient altérer les bits du registre d'état. L'instruction CMP (pour compare) affecte les drapeaux du
registre d'état (instructions de branchement conditionnel afin d'implanter des boucles, des tests ...). La comparaison de 2 nombres
s'effectue en faisant une pseudo-soustraction qui affecte les drapeaux dans le registre d’état :

OF : Overflow Flag
SF : Sign Flag
ZF : Zero Flag
AF : Auxiliary Carry Flag
PF : Parity Flag
CF : Carry Flag

Compte tenu de la ressemblance avec l'instruction SUB, les types des opérandes traités sont :

CMP registre, mémoire


CMP mémoire, registre
CMP registre, registre
CMP mémoire, immédiat
CMP registre, immédiat

Les mnémoniques de sauts conditionnels sont :

Table 1.4. Instructions de branchement en assembleur

Instruction Description Condition Instruction opposée Condition

JA Jump if Above CF = 0 et ZF = 0 JNA CF = 1 ou ZF = 1


JAE Jump if Above or equal CF = 0 JNAE CF = 1

JB Jump if Below CF = 1 JNB CF = 0


JBE Jump if Below or Equal CF = 1 ou ZF = 1 JNBE CF = 0 et ZF = 0

JC Jump if Carry CF = 1 JNC CF = 0


JE Jump if Equal ZF = 1 JNE ZF = 0

JG Jump if Greater ZF = 0 et SF = OF JNG ZF = 1 ou SF != OF


JGE Jump if Greater or Equal SF = OF JNGE SF != OF

JL Jump if Less SF != OF JNL SF = OF


JLE Jump if Less or Equal SF != OF ou ZF = 1 JNLE SF = OF et ZF = 0

JO Jump if Over ow OF = 1 JNO OF = 0


JP Jump if Parity PF = 1 JNP PF = 0

JPE Jump if Parity Even PF = 1 JNPE PF = 0


JPO Jump if Parity Odd PF = 0 JNPO PF = 1

JS Jump if Sign SF = 0 JNS SF = 1


JZ Jump if Zero ZF = 1 JNZ ZF = 0

L'amplitude des sauts conditionnels est limitée à 127 octets vers l'avant et 128 octets vers l'arrière. Pour contourner ce problème, nous
pouvons coupler ce saut conditionnel avec un saut inconditionnel, par exemple :

CMP AX, BX
JZ grandSaut
JMP plusLoin

grandSaut: JMP plusLoin2


….

plusLoin: ….

plusLoin2: ….

https://www.supinfo.com/cours/1CPA/chapitres/09-assembleur-x86 15/32
16/03/2020 Chapitre 09 - L'assembleur x86 | SUPINFO, École Supérieure d'Informatique

Il est à noter, lors de l’émulation des branchements par saut, l’émulateur modifiera votre programme si il y a un saut plus simple en
Contact @SUPINFO
termes de mise à jour des flags conforme à la demande du programme écrit.
ACCUEIL CURSUS COURS ADMISSIONS CAMPUS DOCUMENTATION ANCIENS ENTREPRISES OPEN CAMPUS PUBLICATIONS Naviguer sur la page

6.3 Les boucles

La première manière d'implanter des boucles en utilisant les mnémoniques de sauts conditionnels (JNZ, JMP ...) : cela se rapproche du
while et du do ... while.

La seconde méthode (qui se rapproche plutôt du for) consiste à utiliser le registre CX comme un compteur par l’intermédiaire d’une des
mnémoniques suivantes :

Table 1.5. Instructions de boucle en assembleur

Instruction Description
LOOP Décrémente CX et va à l’étiquette si CX != 0

LOOPE Décrémente CX et va à l’étiquette si CX != 0 et ZF = 1


LOOPNE Décrémente CX et va à l’étiquette si CX != 0 et ZF = 0

LOOPNZ Décrémente CX et va à l’étiquette si CX != 0 et ZF = 0


LOOPZ Décrémente CX et va à l’étiquette si CX != 0 et ZF = 1

JCXZ va à l’étiquette si CX = 0

La construction d'une boucle s’effectue en respectant quelques contraintes :

charger la valeur de la boucle dans le registre CX.


faire précéder la première instruction de la boucle par une étiquette.
terminer la boucle par une instruction de type LOOP qui pointe sur l'étiquette.

L’exemple de code suivant propose une itération avec un loop dont les tours de décrémentation sont gérés par le registre CX :

MOV CX, 5

boucle: INC AX
...
LOOP boucle ; Si CX != 0, nous rebouclons
...

7 LES PROCEDURES EN ASSEMBLEUR 8086

Il peut être utile de placer dans des procédures distinctes des sections de code qui sont appelées plusieurs fois de manière à :

minimiser les recopies de code.


diminuer la taille du code.
augmenter la lisibilité du code.

7.1 La construction

A l’instar de sauts, la mise en place d’une procédure s’effectue en respectant quelques contraintes :

nous devons d’abord écrire son nom (une étiquette mais sans les 2 points) suivi de la directive PROC pour signaler à l’assembleur
qu'il s'agit d'une procédure.
nous plaçons ensuite les instructions assembleur correspondant à l'implantation de la procédure (la dernière étant l’instruction
RET).
nous terminons le code de la procédure par une ligne comportant le nom de la procédure suivi de la directive ENDP.

L'écriture d'une procédure peut se résumer par le squelette de code ci-dessous :

Name PROC

….

RET

Name ENDP

https://www.supinfo.com/cours/1CPA/chapitres/09-assembleur-x86 16/32
16/03/2020 Chapitre 09 - L'assembleur x86 | SUPINFO, École Supérieure d'Informatique

7.2 Les appels Contact @SUPINFO

ACCUEIL CURSUS COURS ADMISSIONS CAMPUS DOCUMENTATION ANCIENS ENTREPRISES OPEN CAMPUS PUBLICATIONS Naviguer sur la page
Comme le montre le programme de la figure ci-dessous, lorsqu’une procédure est implantée, elle peut être appelée par l'instruction
CALL suivie du nom de la procédure. Le mnémonique sauvegarde l’IP dans la pile, indiquant ainsi l'adresse de retour. La procédure est
déroulée jusqu’à l’instruction RET qui restaure l’IP depuis la pile et qui entraîne l’exécution de l’instruction qui suit CALL.

Figure 1.11. Exemple d'un appel de fonction en assembleur

Lorsque nous quittons une procédure appelante pour entrer dans une procédure appelée, nous devons sauvegarder le contexte
d’exécution de la procédure appelante afin de pouvoir reprendre son exécution lors du retour de la procédure appelée. Ce contexte
d’exécution de la procédure appelante est défini par le contenu de l’ensemble des registres qu’elle utilise :

les registres AX, BX …


le registre d’état.

Si nous ne conservons pas l’état de ces registres et si ces derniers sont modifiés par la procédure appelée, le fonctionnement de la
procédure appelante est corrompu. Le moyen le plus couramment utilisé pour conserver ces données est la pile (le segment SS) que
nous manipulons grâce aux instructions suivantes :

PUSH, PUSHA et PUSHF.


POP, POPA et POPF.

L’instruction PUSH permet de conserver une donnée à l’adresse SS:[SP] et de décrémenter SP de 2 (octets). Nous pouvons réaliser 3 types
de PUSH :

avec un nombre : PUSH 10h


avec le contenu d’un registre : PUSH AX
avec le contenu d’une case mémoire : PUSH [BX].

L’instruction PUSHA permet d’empiler le contenu des registres AX, CX, DX, BX, SP, BP, SI et DI. Nous avons donc une équivalence entre
l’instruction PUSHA et l’ensemble des instructions pris dans l’ordre PUSH AX, PUSH CX, PUSH DX, ….

L’instruction PUSHF permet de conserver le contenu du registre d’état à l’adresse SS:[SP]. Comme ce registre a une taille de 16 bits SP est
décrémentée de 2 (octets) à l’issue de cette opération.

L’instruction POP permet de récupérer une donnée à l’adresse SS:[SP] et d’incrémenter SP de 2 (octets). Nous pouvons réaliser 2 types de
POP :

pour stocker l’information récupérée dans un registre : POP AX


pour stocker l’information récupérée dans une case mémoire : POP[BX]

L’instruction POPA effectue le traitement inverse de PUSHA. POPA récupère les informations stockée dans la pile pour les placer dans les
registres DI, SI, BP, SP, BX, DX, CX, et AX. Comme précédemment, nous avons une équivalence entre l’instruction POPA et l’ensemble des
instructions pris dans l’ordre (ordre inversé de PUSHA). Il est à noter que POP SP est ignoré pour ne pas perturber le fonctionnement de
la pile.

L’instruction POPF effectue le traitement inverse de PUSHF. POPF permet de copier le contenu stocké à l’adresse SS:[SP] vers le registre
d’état. Comme ce registre a une taille de 16 bits SP est incrémentée de 2 (octets) à l’issue de cette opération.

8 LES INSTRUCTIONS D’INTERRUPTIONS EN ASSEMBLEUR 8086

https://www.supinfo.com/cours/1CPA/chapitres/09-assembleur-x86 17/32
16/03/2020 Chapitre 09 - L'assembleur x86 | SUPINFO, École Supérieure d'Informatique

Lors d’une utilisation normale d’un ordinateur, il y a en permanence l’exécution d’instructions. Toutes ces instructions ne dépendent pas
Contact @SUPINFO
d’un même programme. En effet, il y a plusieurs programmes qui se partagent le CPU, les entrées/sorties et donc pour exécuter les
instructions, il yCOURS
ACCUEIL CURSUS a un procédé
ADMISSIONScyclique
CAMPUS d’interruption
DOCUMENTATION /ANCIENS
sauvegarde / exécution
ENTREPRISES / restauration.
OPEN CAMPUS PUBLICATIONSIl existe un ensemble d’interruptions
Naviguer sur la: page

Figure 1.12. Hiérarchie des interruptions

Le principe de fonctionnement des interruptions est :

de stopper le programme principal.


de lire la table des vecteurs d’interruption pour connaître l’adresse de la procédure chargée de traiter l’interruption.
de sauvegarder le contexte d’exécution.
d’exécuter la procédure.
de recharger le contexte d’exécution afin de reprendre l’exécution du programme principal.

8.1 Le principe des interruptions matérielles

Le principe d’interruption matérielle est :

Figure 1.13. Principe d'interruption matérielle

Les interruptions matérielles permettent au processeur de réagir aux actions des périphériques externes comme le clavier, la souris …

8.1.1 La prise en compte d’une interruption

Le processeur exécute un programme stocké dans le segment de code de la mémoire. Il doit être capable de réagir à des événements
externes en interrompant le programme en cours pour exécuter une procédure de traitement de l’événement. Ce mécanisme nécessite
l’adjonction d’un composant appelée contrôleur d’interruption sur lequel sont branchés les périphériques susceptibles de demander au
processeur d’effectuer des traitements en réaction à leur fonctionnement (le clavier, la souris, le disque dur …).

Si nous rentrons dans les détails, le contrôleur d’interruption est composé de 2 circuits 8259A mis en cascade. Dont chaque fil, appelé
IRQ ( Interrupt ReQuest ) est raccordé à un périphérique (ou un ensemble de périphériques).

Figure 1.14. Circuit des IRQ

https://www.supinfo.com/cours/1CPA/chapitres/09-assembleur-x86 18/32
16/03/2020 Chapitre 09 - L'assembleur x86 | SUPINFO, École Supérieure d'Informatique

Contact @SUPINFO

ACCUEIL CURSUS COURS ADMISSIONS CAMPUS DOCUMENTATION ANCIENS ENTREPRISES OPEN CAMPUS PUBLICATIONS Naviguer sur la page

Si nous prenons l’exemple du clavier, celui-ci est raccordé à l’IRQ 1. Lorsque le clavier sollicite l’attention du processeur, celui-ci envoie
un signal sur cette patte. Le numéro de l’interruption est alors mis sur le bus de données pour être transmis vers le processeur. Lorsque
le bus de données est stable, le contrôleur d’interruption envoie un signal IRQ Request vers le processeur pour lui demander de tenir
compte du clavier. Le processeur indique par un INT ACKNOWLEDGE qu’il a pris en compte le signal d’interruption : le contrôleur
d’interruption désactive alors ce signal pour pouvoir en reprendre un en compte ultérieurement.

Figure 1.15. IRQ clavier

8.1.2 La sauvegarde des contextes

Avant le traitement de l’IRQ, le processeur exécutait un programme, il existe un contexte d’exécution correspondant à l’état des
différents registres au moment de cette interruption (en particulier le compteur ordinal qui pointe la prochaine instruction à exécuter).
Le processeur lit d’abord une zone mémoire appelée la table des vecteurs d’interruption, afin de connaître l’adresse de la procédure de
traitement en fonction du numéro de l’interruption. Le processeur exécute alors la première instruction de la procédure. Les premières
instructions consistent généralement à sauvegarder le contexte dans la pile avant d’exécuter la procédure de traitement de l’interruption
proprement dite. Lorsque le traitement proprement dit est terminé, nous rechargeons le contexte d’exécution depuis la pile (le compteur
ordinal pointe sur l’instruction du programme principal dont l’exécution pourra reprendre) et nous exécutons l’instruction IRET ( Interrupt
RETurn ). Ce procédé de sauvegarde est illustré par les schémas de la figure ci-dessous.

Figure 1.16. Sauvegarde d'un contexte

https://www.supinfo.com/cours/1CPA/chapitres/09-assembleur-x86 19/32
16/03/2020 Chapitre 09 - L'assembleur x86 | SUPINFO, École Supérieure d'Informatique

Certaines des interruptions matérielles (par exemple, le clavier) peuvent être masquées (le processeur peut ne pas en tenir compte) alors
Contact @SUPINFO
que d’autres (défaut de circuit RAM) ne peuvent pas l’être.
ACCUEIL CURSUS COURS ADMISSIONS CAMPUS DOCUMENTATION ANCIENS ENTREPRISES OPEN CAMPUS PUBLICATIONS Naviguer sur la page
Ce mécanisme est utilisé lorsque le processeur doit effectuer un traitement critique. Cela concerne par exemple la commutation entre 2
processus dans un système d’exploitation multitâches (des informations critiques doivent être sauvegardées et le processeur ne doit en
aucun cas être dérangé pendant cette phase).

8.2 Le principe des interruptions logicielles

Le principe d’interruption matérielle est :

Figure 1.17. Principe d'interruption logicielle

8.2.1 L’écran

Ce principe appliqué au traitement de signaux électroniques externes a été étendu au traitement des signaux logiciels internes. Le
programmeur a en effet la possibilité d’invoquer l’exécution de procédures toute faites (nous parlons d’interruption par abus de langage)
en utilisant l’instruction INT suivi du numéro de l’interruption à exécuter, par exemple :

INT 10H

Le processeur interrompt alors le programme principal, sauvegarde le contexte d’exécution courante, et se branche sur la procédure de
traitement selon le principe évoqué précédemment. Les interruptions logicielles sont en réalité des procédures toutes faites, mises à la
disposition des programmeurs pour faciliter le contrôle des organes de l’ordinateur (disque dur, clavier …).

Nous distinguons :

les interruptions du BIOS (Basic Input Output System) qui sont implantées par le constructeur de la carte mère (les 32 premières
interruptions).
les interruptions système (DOS, Windows, Linux …) qui sont chargées en mémoire lors du chargement du système d’exploitation
(les 32 suivantes,). Nous allons en étudier 2 d’entre elles qui gèrent le clavier et l’écran.

L’écran peut être contrôlé par l’interruption n°10h (BIOS) ou l’interruption n°21h (DOS).

L’interruption 21h cache un ensemble de fonctions. Le numéro de la fonction utilisée et les paramètres de la fonction doivent être placés
dans certains registres avant l’instruction INT 21h.

Si nous souhaitons afficher un caractère à l’écran, nous devons utiliser la fonction 06h. Pour cela, nous devons placer la valeur 06h dans
le registre AH et le code ASCII du caractère à afficher dans le registre DL avant d’appeler l’interruption 21h, par exemple :

MOV AH, 6H
MOV DL, ‘A’
INT 21h

La routine de traitement lit d’abord le contenu de AH pour déterminer qu’il s’agisse de la fonction 06h puis elle lit le registre DL pour
déterminer le caractère qui doit être affiché à la position courante du curseur sur l’écran.

https://www.supinfo.com/cours/1CPA/chapitres/09-assembleur-x86 20/32
16/03/2020 Chapitre 09 - L'assembleur x86 | SUPINFO, École Supérieure d'Informatique

Pour l’affichage des caractères, nous utilisons la fonction 09h. Pour cela, il faut effectuer les affectations ci-dessous avant d’appeler
Contact @SUPINFO
l’interruption 21h :
ACCUEIL CURSUS COURS ADMISSIONS CAMPUS DOCUMENTATION ANCIENS ENTREPRISES OPEN CAMPUS PUBLICATIONS Naviguer sur la page
placer la valeur 09h dans le registre AH.
l’offset de cette même chaîne de caractères dans DX.

La chaîne de caractères est alors affichée à la position courante du curseur sur l’écran.

ORG 100h

MOV AH, 09h


MOV DX, OFFSET message

INT 21h
RET

message DB ‘Bonjour Monde $’

L’affichage d’une chaine de caractères peut de faire aussi avec une interruption. Pour cela, nous utilisons la fonction 40h. Il faut effectuer
les affectations ci-dessous avant d’appeler l’interruption 21h :

placer la valeur 40h dans le registre AH.


placer la valeur 01h ou 02h dans le registre BX.
placer le nombre de caractères de la chaine dans CX.
l’offset de cette même chaîne de caractères dans DX.

La chaîne de caractères est alors affichée à la position courante du curseur sur l’écran.

ORG 100H

MOV AH, 40h


MOV BX, 02h
MOV CX, NBcaracteres
MOV DX, offset message
INT 21H
RET

message DB "Bonjour Monde!!"


Nbcaracteres DW 15

Il est toujours possible de se positionner ou nous voulons dans l’écran d’affichage, et pour cela il faut positionner le curseur. Nous
utilisons la fonction 02h en effectuent les affectations ci-dessous avant d’appeler l’interruption 10h :

placer la valeur 02h dans le registre AH.


placer la valeur de ligne dans DH.
placer la valeur de la colonne dans DL.

La chaîne de caractères pourra s’afficher à la position définie par DH et DL.

ORG 100H

MOV AH,02h
MOV DH,05h
MOV DL,20h
INT 10H
RET

8.2.2 Le clavier

Le clavier peut être contrôlé par l’interruption de la fonction 16h du BIOS ou par l’interruption de la fonction 21h du DOS. L’interruption
16h est également composée de plusieurs fonctions mais 2 nous intéressent plus particulièrement :

la fonction 00h qui permet de récupérer le code de la touche qui a été frappée au clavier.
la fonction 01h qui permet de vérifier si une touche a été frappée au clavier.

Pour lire la touche qui a été frappée sur le clavier, il faut utiliser la fonction 0h.

Pour cela, nous écrivons la valeur 0h dans AH puis nous exécutons l’instruction INT 16h.

https://www.supinfo.com/cours/1CPA/chapitres/09-assembleur-x86 21/32
16/03/2020 Chapitre 09 - L'assembleur x86 | SUPINFO, École Supérieure d'Informatique

Lors de son exécution, cette routine retire du buffer du clavier, le code de la touche qui a été tapé, pour le mettre à notre disposition :
Contact @SUPINFO

le registre AL contient le code ASCII de la touche.


ACCUEIL CURSUS COURS ADMISSIONS CAMPUS DOCUMENTATION ANCIENS ENTREPRISES OPEN CAMPUS PUBLICATIONS Naviguer sur la page
le registre AH contient le code clavier de la touche.

Pour tester si une touche a été frappée sur le clavier, il faut utiliser la fonction 1h.

Comme précédemment, nous écrivons la valeur 1h dans AH puis nous exécutons l’instruction INT 16h.

Si un caractère est présent dans le buffer, cette routine met le drapeau ZF à 0 (sinon il est à 1) puis elle copie depuis le buffer du clavier,
le code de la touche qui a été tapé, pour le mettre à notre disposition :

le registre AL contient le code ASCII de la touche.


le registre AH contient le code clavier de la touche.

Si un programme contient une boucle qui teste de façon incessante si une touche a été frappée sur le clavier :

si une touche est effectivement frappée, nous exécutons la procédure correspondante


si ce n’est pas le cas, nous retournons au début de la boucle et nous recommençons le test.

Ce type de programme fait de l’attente active. Par conséquent, il teste de façon répétée si un événement est survenu pour déclencher
une action au lieu d’être activée par l’événement lui-même. Il est généralement conseillé d’éviter ce type de programmation car elle
conduit à gaspiller du temps CPU et par voie de conséquence à dégrader les performances d’un programme Assembleur.

Il est préférable d’adopter une technique de programmation événementielle où le programme réagit à des événements externes.

Pour réaliser ce type de programmation en assembleur, il est nécessaire de dérouter les interruptions.

Ce déroutement s’effectue simplement en modifiant l’adresse contenue dans la table des vecteurs d’interruption.

Si nous prenons l’exemple du clavier, celui-ci est d’abord géré par l’interruption 9h qui est appelée par le contrôleur d’interruption :

le traitement par défaut consiste à copier les codes concernant la touche qui a été frappée dans un buffer.
il est possible d’implanter notre propre procédure de traitement puis de modifier l’adresse de la procédure associée à l’interruption
9h de manière à ce que notre procédure soit appelée lorsqu’une touche est saisie.

Cette technique était utilisée dans les anciens jeux vidéo pour gagner en fluidité dans le contrôle du jeu.

Il est possible de faire du masquage d’interruption grâce à l’instruction CLI ( CLear Interrupt ) qui a pour effet de mettre à 0 le bit IF du
registre d’état.

L’instruction STI ( SeT Interruption ) permet de rendre le processeur sensible aux interruptions masquables.

9 LES PROGRAMMES EN ASSEMBLEUR 8086

Pour construire un fichier en ASM, il faut adopter la rigueur de programmation habituelle, car il subira ensuite une transformation pour
devenir un programme exécutable (Pour un programme assembleur, cette transformation est nommée assemblage). Une fois
l’assemblage fait sans erreur, nous avons un fichier dit objet (écrit exclusivement en binaire sur des octets consécutifs en mémoire,
découpé en segment de code). Si pour fonctionner, le programme a besoin d’autres instructions provenant d’un autre programme, il
faudra lier tous les codes objets entre eux avec un éditeur de lien.

Les instructions (codage du code-opérateur comprenant le mnémonique suivi du ou des valeurs immédiates, registres, adresses, …) sont
écrites les unes en dessous des autres permettant à l'assembleur de différencier les commandes à faire. Nous distinguons 2 types de
format, les fichiers pour faire des programmes COM et des fichiers pour faire des programmes EXE.

Soit le programme en format COM suivant :

segmentprogramme segment use16

assume CS: segmentprogramme, DS: segmentprogramme, SS: segmentprogramme

ORG 100H

programme:
MOV AH,02h
MOV DH,05h
MOV DL,20h

INT 10H

MOV AH, 40h


MOV BX, 02h
MOV CX, NBcaracteres
MOV DX, offset message
https://www.supinfo.com/cours/1CPA/chapitres/09-assembleur-x86 22/32
16/03/2020 Chapitre 09 - L'assembleur x86 | SUPINFO, École Supérieure d'Informatique

Contact @SUPINFO
INT 21H

ACCUEIL
RET CURSUS COURS ADMISSIONS CAMPUS DOCUMENTATION ANCIENS ENTREPRISES OPEN CAMPUS PUBLICATIONS Naviguer sur la page

message DB "Bonjour Monde!!"


NBcaracteres DW 15

segmentprogramme ends
end programme

Un fichier COM ne comporte qu’un segment nous le voyons sur la figure ci-dessus par l’instruction : segmentprogramme segment use16.

Cette instruction Indique au compilateur le début de l’adresse du segment nommé segmentprogramme. use16 indique que les adresses
de segment et de l’offset sont codées sur 16 bits et non sur 8 bits. Le segment est pointé initialement par CS, DS et SS. Il faut rappeler
dans le programme ces pointages et l’instruction assume permet de faire un espace de nom sur DS. L’espace de nom permet d’éviter
d’écrire systématiquement les variables avec l’expression ds:. Ensuite pour construire le code objet, le compilateur cherche quel registre
l’utilisateur utilise, il veut un registre de segment. Il récupère le segment pointé par assume. Les instructions segmentprogramme ends et
end programme permettent de donner les indications nécessaire de fin pour construire l’ensemble des codes objets.

Pour un fichier de type EXE, il faut distinguer les partie des code objets produits. Il se base sur le comportement dynamique d’un
programme et le construit comme un processus et sépare les données du programme et de la pile des appels.

segmentprogramme segment use16

assume CS: segmentprogramme, DS: donnees, SS: pile

programme:
MOV AH,02h
MOV DH,05h
MOV DL,20h

INT 10H ; Le décalage est fait

MOV AX, donnees


MOV DS, AX ; DS n’accepte que de l’adressage par registre
MOV AH, 09h
MOV DX, offset message

INT 21H

MOV AH,4Ch ; Une obligation pour les fichiers EXE

INT 21H

RET
segmentprogramme ends

donnees segment use16


message DB 'Bonjour Monde!! $' ; C’est une chaine
Donnees ends

pile segment stack ;Déclaration de la pile stack mot réservé.


taille db 256 DUP (?) ;Réservation de place 256 caractères.
pile ends
end programme

Un fichier EXE comporte une distinction entre le programme, ses données et la pile des appels.

Figure 1.18. Pointeur de zone pour un programme en assembleur 8086

https://www.supinfo.com/cours/1CPA/chapitres/09-assembleur-x86 23/32
16/03/2020 Chapitre 09 - L'assembleur x86 | SUPINFO, École Supérieure d'Informatique

Contact @SUPINFO

ACCUEIL CURSUS COURS ADMISSIONS CAMPUS DOCUMENTATION ANCIENS ENTREPRISES OPEN CAMPUS PUBLICATIONS Naviguer sur la page

Les segments de pile, de données, de code, … sont dans leur zone mémoire. Les registres CS DS SS et ES sont les pointeurs d’adresse des
segments d'instructions. ASSUME indique à l'assembleur où les segments sont situés.

10 L’OUTIL EMU8086

Lorsque nous démarrons l’outil Emu 8086, l'application nous propose une interface.

Figure 1.19. Interface initiale de l’outil Emu 8086

Si nous appuyons sur le bouton "Code Examples", nous avons accès à une liste d'exemple. Le programme Hello World étant trop
complexe à ce stade de l’apprentissage (il faut d'abord décrire le fonctionnement de la carte vidéo pour comprendre cet exemple), nous
allons nous orienter vers un programme de calcul avec des "ADD/ SUB". Pour utiliser les opérations, nous devons au préalable charger
dans les registres des valeurs, et nous le ferons avec l’instruction MOV et les registres de bases AX et BX.

Figure 1.20. Etapes pour obtenir une fenêtre d’édition

https://www.supinfo.com/cours/1CPA/chapitres/09-assembleur-x86 24/32
16/03/2020 Chapitre 09 - L'assembleur x86 | SUPINFO, École Supérieure d'Informatique

Contact @SUPINFO

ACCUEIL CURSUS COURS ADMISSIONS CAMPUS DOCUMENTATION ANCIENS ENTREPRISES OPEN CAMPUS PUBLICATIONS Naviguer sur la page

Pour une création d’édition d’un programme, nous le faisons en 3 étapes, New, Empty workspace et valider.

Chaque instruction assembleur (mnémonique) possède une correspondance en langage machine, appelée code opérateur (CodeOp), qui
peut être codé sur un ou plusieurs octets. Cette correspondance est spécifiée par le constructeur - Intel - dans son databook ce qui
permet au programmeur de développer leur assembleur et/ou leur émulateur.

Les instructions opération registre, valeur sont dites à adressage immédiat car nous indiquons "en dur" la valeur qui doit être chargée
dans le registre :

MOV AX,15h ; CodeOp = B815

Les instructions opération registre, registre sont dites de registres car les données, sur lesquelles les opérations sont effectuées, sont
contenues dans les registres :

MOV BX, AX ; CodeOp = 8BD8

Dans ces 2 cas, il n'y a pas de construction d'adresses sur 20 bits puisque nous ne faisons pas intervenir la mémoire, ces instructions
sont rapides à exécuter.

Figure 1.21. Programme dans la fenêtre d’édition

Pour générer et commencer à exécuter le programme de la figure ci-dessus, il faut cliquer sur EMULATE. L'assembleur attribue aux
instructions traduite en langage machine des adresses relatives. Le processus d’émulation respecte les conditions architecturales car les
adresses sont attribuées de façon séquentielle à partir du début du programme. C’est la raison pour laquelle une origine doit être
définie; fait par l’instruction ORG 100h.

Un programme, pour être exécuté est chargé en mémoire par le système d’exploitation. Le DOS distingue 2 modèles de programmes :

1. les fichiers exécutables COM (utilisant un seul segment dans la mémoire de taille 64 Ko).
2. les fichiers exécutables EXE (limités que par la mémoire disponible dans l’ordinateur).

https://www.supinfo.com/cours/1CPA/chapitres/09-assembleur-x86 25/32
16/03/2020 Chapitre 09 - L'assembleur x86 | SUPINFO, École Supérieure d'Informatique

Le DOS charge le fichier COM et lui alloue toute la mémoire disponible. Mais si la mémoire est insuffisante, il annule le chargement en
Contact @SUPINFO
l’indiquant à l’utilisateur.
ACCUEIL CURSUS COURS ADMISSIONS CAMPUS DOCUMENTATION ANCIENS ENTREPRISES OPEN CAMPUS PUBLICATIONS Naviguer sur la page
Dès que le chargement se fait, le DOS crée un PSP ( Program Segment Prefix ) du programme lui-même, au début du bloc de mémoire,
représentant une taille 100h d’où l’obligation de placer org 100h dans les programmes pour ne pas corrompre le PSP.

Un PSP contient des informations comme le nom et le type d’extension du programme, des paramètres d’entrées, …

Figure 1.22. Fenêtres de contrôle lors d’une exécution d’un programme

Pour désigner une instruction contenue dans une case de la mémoire de 1 Mo, nous avons besoin d'une adresse codée sur 20 bits (cela
dépasse les capacités des registres internes du 80x86).

Pour contourner ce problème, l'adresse est codée avec 2 registres :

le registre CS ( Code Segment ) contient l'adresse de la base du segment de code.


le registre IP ( Instruction Pointer) contient une adresse relative à cette base (nous parlons de déplacement ou d’offset).
l'adresse absolue (ou adresse effective) est obtenue en utilisant le couple d’un segment (numéro du segment, déplacement) soit :
CS * 16 10 + IP.

Pour accéder à un octet particulier dans un segment, il suffit de compter le décalage de cet octet par rapport au début du segment.
L'adresse d'un octet (en hexadécimale) se note AAAA:BBBB où AAAA est l'adresse de segment et BBBB est l’offset. Par exemple, le 17ième
octet de la RAM (le numéro 16) est situé à l'adresse 0000:0010. L’octet 0000:0100 est l'octet numéro 256.

Si l'adresse de l'octet est 12F3:0230, alors son adresse effective est : 12F3 16 * 10 16 + 0230 16 = 13160 16 . Un octet n'a pas une adresse
unique. Par exemple, l'octet numéro 8810 peut être adressé par :

1. 0000:0058
2. 0001:0048
3. 0002:0038
4. 0003:0028
5. 0004:0018
6. 0005:0008

Figure 1.23. Correspondance Case mémoire dans un programme ASM

https://www.supinfo.com/cours/1CPA/chapitres/09-assembleur-x86 26/32
16/03/2020 Chapitre 09 - L'assembleur x86 | SUPINFO, École Supérieure d'Informatique

Contact @SUPINFO

ACCUEIL CURSUS COURS ADMISSIONS CAMPUS DOCUMENTATION ANCIENS ENTREPRISES OPEN CAMPUS PUBLICATIONS Naviguer sur la page

Appuyons sur le bouton "Single Step" afin de lancer une exécution pas-à-pas du programme. Chaque clik effectué représente une
progression dans les instructions.

La première instruction (MOV AX, 5) est chargée, décodée et exécutée par le processeur :

le registre AX contient la valeur 00 05h.


le registre IP contient la valeur 0103h (IP passe de 0100h à 0103h car MOV AX, 5 est codé sur 3 octets).

La prochaine instruction pointée par IP (MOV BX, 10) est surlignée dans les différents écrans.

Figure 1.24. Exécution d’une instruction MOV Ax, 5 dans un programme ASM

Appuyons sur le bouton "Single Step" pour exécuter la deuxième instruction (MOV BX, 10) :

le registre BX contient la valeur 00 10h.


le registre IP contient la valeur 0106h (IP passe de 103h à 0106h car MOV BX, 10 est codé sur 3 octets).

Figure 1.25. Exécution d’une instruction MOV Bx, 10 dans un programme ASM

https://www.supinfo.com/cours/1CPA/chapitres/09-assembleur-x86 27/32
16/03/2020 Chapitre 09 - L'assembleur x86 | SUPINFO, École Supérieure d'Informatique

Contact @SUPINFO

ACCUEIL CURSUS COURS ADMISSIONS CAMPUS DOCUMENTATION ANCIENS ENTREPRISES OPEN CAMPUS PUBLICATIONS Naviguer sur la page

Nous exécutons la troisième instruction (ADD AX, BX) :

la fenêtre ALU affiche le contenu des 2 registres temporaires d'entrées et le résultat de l'opération.
le registre AX contient la valeur 000Fh (0005h + 000Ah = 000Fh).
le registre IP contient la valeur 0108h (IP passe de 0106h à 0108h car ADD AX, BX est codé sur 2 octets).

Figure 1.26. Exécution d’une instruction ADD Ax, Bx dans un programme ASM

Nous exécutons la quatrième instruction (SUB AX, 1) :

la fenêtre ALU affiche le contenu des 2 registres temporaires d'entrées et le résultat de l'opération.
le registre AX contient la valeur 000Fh (000Fh - 0001h = 000Eh).
le registre IP contient la valeur 0010Bh (IP passe de 0108h à 0010Bh car SUB AX, 1 est codé sur 3 octets).

Figure 1.27. Exécution d’une instruction SUB Ax, 1 dans un programme ASM

https://www.supinfo.com/cours/1CPA/chapitres/09-assembleur-x86 28/32
16/03/2020 Chapitre 09 - L'assembleur x86 | SUPINFO, École Supérieure d'Informatique

Contact @SUPINFO

ACCUEIL CURSUS COURS ADMISSIONS CAMPUS DOCUMENTATION ANCIENS ENTREPRISES OPEN CAMPUS PUBLICATIONS Naviguer sur la page

Nous exécutons la cinquième instruction (RET). Cette instruction est équivalente à effectuer POP IP :

nous dépilons la valeur stockée dans la pile à la position SS:SP (adresse : SS * 16 10 + SP) pour la charger dans le registre IP. SS:SP (=
0B56h:FFFEh) et le mot (2 octets consécutifs) stocké à cette adresse valent 0000h.
puis IP = 0000h, la prochaine instruction exécutée est à l'adresse CS:IP = 0B56h:0000h.
nous modifions la valeur de SP car nous avons dépilé un élément. SP = FFFEh + 0002h = 10000h soit 0000h car SP est un registre 16
bits.

Figure 1.28. Préparation d''une exécution d’une instruction RET dans un programme ASM

Nous appuyons sur single step et nous exécutons une instruction non saisie dans notre programme (INT 020h) qui a été
automatiquement ajoutée par le système d'exploitation (de même que la valeur qui était empilée et la valeur des registres SS et SP).

Figure 1.29. Exécution d’une instruction INT 20h dans un programme ASM

https://www.supinfo.com/cours/1CPA/chapitres/09-assembleur-x86 29/32
16/03/2020 Chapitre 09 - L'assembleur x86 | SUPINFO, École Supérieure d'Informatique

Contact @SUPINFO

ACCUEIL CURSUS COURS ADMISSIONS CAMPUS DOCUMENTATION ANCIENS ENTREPRISES OPEN CAMPUS PUBLICATIONS Naviguer sur la page

INT 020h donne l'ordre au processeur d'exécuter l'interruption (routine ou procédure) numéro 20h (l’ordre de INT 020h est de quitter le
système d’exploitation). Le processeur modifie le contenu de ses registres car il saute dans une autre zone mémoire puis il exécute cette
instruction qui consiste simplement à terminer le programme et à rendre la main au système d'exploitation (ici une émulation du DOS).

Figure 1.30. Exécution d’une instruction de fin pour un programme ASM

https://www.supinfo.com/cours/1CPA/chapitres/09-assembleur-x86 30/32
16/03/2020 Chapitre 09 - L'assembleur x86 | SUPINFO, École Supérieure d'Informatique

Contact @SUPINFO

11 L’ADRESSAGE
ACCUEIL CURSUS COURS ADMISSIONS CAMPUS DOCUMENTATION ANCIENS ENTREPRISES OPEN CAMPUS PUBLICATIONS Naviguer sur la page

Nous avons vu 2 modes d'adressages. Ces 2 modes ne font pas intervenir la mémoire centrale : Le mode immédiat où un opérande est
un nombre codé sur 8 ou 16 bits directement dans le codeop :

MOV AX, 15 (CodeOp = B815)

Le mode par registre qui fait intervenir 2 registres :

MOV AX, BX (CodeOp = 8BD8)

Les instructions d'un programme sont pointées par le registre IP qui contient une adresse relative au segment de code (Code Segment ou
CS) avec :

l'adresse de base est stockée dans CS.


l'adresse absolue de l'instruction est CS:IP = CS * 16 10 + IP.

L’adressage des données dans DS peut s’effectuer de différentes manières (en utilisant différentes combinaisons) et prenons DEP est un
nombre qui correspond à un décalage en mémoire, exprimé en octets :

DS : DEP, DS : BX, DS : SI, DS : DI, DS : BX+DEP, DS : SI+DEP, DS : DI+DEP, DS : BX+SI, DS : BX+DI, DS : BX+SI+DEP, DS : BX+DI+DEP

Nous pouvons adresser des données dans la pile (Stack Segment ou SS) ou dans le segment supplémentaire ( Extra Segment ou ES). Nous
avons les combinaisons supplémentaires suivantes et prenons DEP est un nombre qui correspond à un décalage en mémoire, exprimé
en octets :

ES : DEP, ES : BX, ES : SI, ES : DI, ES : BX+DEP, ES : SI+DEP, ES : DI+DEP, ES : BX+SI, ES : BX+DI, ES : BX+SI+DEP, ES : BX+DI+DEP

D’un point de vue programmation, ces adressages des données peuvent être utilisés à l’aide de l’instruction MOV.

D’un point de vue syntaxique, nous distinguons ce type d’adressage de ceux évoqués précédemment grâce à l’utilisation des crochets [ ]
qui entoure la seconde partie de l’adresse, par exemples :

MOV DS:[BX], 10 signifie que nous stockons 10 dans la case dont l’adresse est DS:BX (soit DS * 16 10 + BX). le segment concerné est
DS, il n’est pas nécessaire de l’indiquer car il est sous-entendu et donc MOV [BX], 4 est équivalent à MOV DS:[BX], 4
MOV AX, DS:[BX+DI+0x10h] signifie qu'il faut copier le contenu de la case mémoire d’adresse DS:BX+DI+0x10h dans le registre AX.
MOV ES:[BX+SI], DX permet de stocker le contenu du registre DX dans la case mémoire d’adresse ES:[BX+SI].
MOV CX, SS:[BP+0x02h] permet de copier, dans le registre CX, le contenu dans la case mémoire d’adresse SS:[BP+0x02h].

Nous avons utilisé les instructions ADD, SUB et ADC en respectant l’une des 2 syntaxes (qui correspondent respectivement au mode
immédiat et au mode par registre) :

ADD/SUB/ADC registre, immédiat


ADD/SUB/ADC registre, registre

Ces instructions peuvent s’appliquer en mode d’adressage en mémoire :

ADD/SUB/ADC registre, mémoire


ADD/SUB/ADC mémoire, registre
ADD/SUB/ADC mémoire, immédiat

Les instructions MUL, IMUL, DIV et IDIV ne supportent pas le mode immédiat. Ces instructions s’utilisent uniquement en mode par
registre et en mode en mémoire. Nous avons les syntaxes suivantes :

MUL/IMUL/DIV/IDIV registre
MUL/IMUL/DIV/IDIV mémoire

Pour spécifier si le pointeur manipule un mot ou un octet (utile pour opération de division et de multiplication). Nous devons ajoutons
une information supplémentaire devant le pointeur :

si le pointeur manipule un mot, nous le faisons précéder de WORD PTR ou w. :

MOV WORD PTR ES:[BX+DI+0x10h], AX

dans le cas contraire, nous le faisons précéder de BYTE PTR ou b. :

DIV b.ES:[BX+DI+0x10h]

Il est important de noter qu’il n’existe pas d’instruction avec un MOV pour transférer le contenu d’un registre de segment vers un autre
registre de segment. Donc, il est indispensable de passer par un registre de données pour transférer les registres de segment.

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

https://www.supinfo.com/cours/1CPA/chapitres/09-assembleur-x86 31/32
16/03/2020 Chapitre 09 - L'assembleur x86 | SUPINFO, École Supérieure d'Informatique

MOV AL,[15h]
Contact @SUPINFO

= MOV AL,DS:[15h] ; (CodeOP A01500)


ACCUEIL CURSUS COURS ADMISSIONS CAMPUS DOCUMENTATION ANCIENS ENTREPRISES OPEN CAMPUS PUBLICATIONS Naviguer sur la page
= MOV AL,DS:15h ; (CodeOP 3E A01500)

MOV AX,ES:[15h] = MOV AX,ES:15h ; (CodeOp 26 A11500)

Adressage basé : l'opérande est une case mémoire dont l'adresse est donnée par BX (avec DS par défaut) ou BP (avec SS par défaut) :

MOV AH,[BX]

= MOV AH,DS[BX] ; (CodeOp 8A27)


= MOV AH,DS:[BX] ; (CodeOp 3E8A27)

MOV AL,[BP]

= MOV AL,SS[BP] ; (CodeOp 8A4600)


= MOV AL,SS:[BP] ; (CodeOp 368A4600)

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 mnémonique
spécifique) :

MOV AH,[SI]

= MOV AH,DS[SI] ; (CodeOp 8A24)


= MOV AH,DS:[SI] ; (CodeOp 3E8A24)

Adressage basé et indexé :

MOV AH,[BX+DI]

= MOV AH,DS[BX+DI] ; (CodeOp 8A21)


= MOV AH,DS:[BX+DI] ; (CodeOp 3E8A21)

MOV [BP+SI],AH

= MOV SS[BP+SI],AH ; (CodeOp 8822)


= MOV SS:[BP+SI],AH ; (CodeOp 368822)

Adressage basé avec déplacement :

MOV AH,[BX+15h]

= MOV AH,DS[BX+15h] ; (CodeOp 8A6715)


= MOV AH,DS:[BX+15h] ; (CodeOp 3E8A6715)

Adressage indexé avec déplacement :

MOV AH,[DI+15h]

= MOV AH,DS[DI+15h] ; (CodeOp 8A6515)


= MOV AH,DS:[DI+15h] ; (CodeOp 3E8A6515)

Adressage basé et indexé avec déplacement :

MOV AH,[BX+SI+15h]

= MOV AH,DS[BX+SI+15h] ; (CodeOp 8A6015)


= MOV AH,DS:[BX+SI+15h] ; (CodeOp 3E8A6015)

Le support de cours 1CPA Essentiel proposé dans la formation SUPINFO est maintenant terminé. Il a proposé une vision Hardware
Hardware (UAL, registres, mémoires et bus basés sur une architecture pédagogique) et Hardware Software (Assembleur).

A propos de SUPINFO | Contacts & adresses | Enseigner à SUPINFO | Presse | Conditions d'utilisation & Copyright | Respect de la vie privée | Investir

SUPINFO International University


Ecole d'Informatique - IT School
École Supérieure d'Informatique de Paris, leader en France
La Grande Ecole de l'informatique, du numérique et du management
Fondée en 1965, reconnue par l'État. Titre Bac+5 certifié au niveau I.
SUPINFO International University is globally operated by EDUCINVEST Belgium - Avenue Louise, 534 - 1050 Brussels

https://www.supinfo.com/cours/1CPA/chapitres/09-assembleur-x86 32/32

Vous aimerez peut-être aussi