0% ont trouvé ce document utile (0 vote)
3 vues95 pages

Software

Le document traite du logiciel, en abordant des concepts fondamentaux tels que les langages machine, les interpréteurs, et les compilateurs. Il explore également l'architecture des ordinateurs, l'organisation des PC, et la structure des programmes en langage d'assemblage. Enfin, il présente des notions sur la pile et les modes d'adressage mémoire.

Transféré par

Wassim El Falou
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
3 vues95 pages

Software

Le document traite du logiciel, en abordant des concepts fondamentaux tels que les langages machine, les interpréteurs, et les compilateurs. Il explore également l'architecture des ordinateurs, l'organisation des PC, et la structure des programmes en langage d'assemblage. Enfin, il présente des notions sur la pile et les modes d'adressage mémoire.

Transféré par

Wassim El Falou
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

Le logiciel ou Software

Pascal FOUGERAY
Toutes les données, images, valeurs, phrases de ce document ne sont pas ma propriété dite “intellec-
tuelle”. Si vous voulez récupérer ce document et le façonner à votre goût, cela ne me dérange nullement. Je
n’ai presque rien inventé hormis certains exemples de travaux pratiques, j’ai beaucoup “pioché” et “trié”
dans différentes littératures les informations s’y trouvant.

Bonne lecture. . .

1
Table des matières

I Le Logiciel ou Software 8
1 Introduction 9
1.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.2 Définition d’un langage machine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.3 L’interpréteur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.4 Le compilateur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.5 Le langage d’assemblage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.5.1 Pour l’architecture de type x86 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.5.2 Pour l’architecture de type alpha . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
1.5.3 Pour l’architecture de type sparc . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

2 Architecture d’un ordinateur de type PC 13


2.1 Schéma général des fonctions de traitement . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.2 Organisation logique d’un ordinateur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.2.1 La mémoire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.2.2 L’organe d’entrée . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.2.3 Le bloc de calcul . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.2.4 L’organe de sortie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.2.5 L’organe de commande . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

3 Organisation d’un PC 16
3.1 Le Microprocesseur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
3.2 La Mémoire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
3.3 Registres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
3.3.1 Registres de travail . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
3.3.2 Registres de segment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
3.3.3 Améliorations des registres du 80286 . . . . . . . . . . . . . . . . . . . . . . . . 18
3.3.4 Améliorations des registres du 80386 et 486 . . . . . . . . . . . . . . . . . . . . . 18
3.3.5 Améliorations des registres depuis le P2 . . . . . . . . . . . . . . . . . . . . . . . 19
3.4 Les registres généraux des microprocesseurs x386 et plus . . . . . . . . . . . . . . . . . . 19
3.5 Segmentation mémoire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20

4 Structure d’un programme en langage d’assemblage x386. 21


4.1 Exemple de programme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
4.2 Composition d’une ligne de code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
4.3 Les directives d’assemblage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
4.3.1 Les directives de segmentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
4.3.2 Les directives de constantes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
4.4 Les labels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
4.5 Les instructions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
4.6 Les opérandes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
4.7 Les commentaires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26

2
5 La pile 27
5.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
5.2 Les instructions pushl et popl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
5.3 Le principe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
5.4 L’appel d’une fonction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
5.5 La pile lors de la transmission de paramètres . . . . . . . . . . . . . . . . . . . . . . . . . 28

6 Modes d’adressage mémoire 30


6.1 Définition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
6.2 Adressage immédiat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
6.3 Adressage indirect . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
6.4 Adressage basé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
6.5 Adressage indexé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
6.6 Les combinaisons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
6.6.1 Adressage indexé et basé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
6.6.2 Adressage basé et déplacement direct ou immédiat . . . . . . . . . . . . . . . . . 33
6.6.3 Adressage indexé et déplacement direct ou immédiat . . . . . . . . . . . . . . . . 33
6.6.4 Adressage basé, indexé et déplacement direct ou immédiat. . . . . . . . . . . . . . 33
6.6.5 Remarques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
6.6.6 Remarque 2, mode protégé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
6.7 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34

7 Données en mémoire 35
7.1 Base de calcul . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
7.2 Données initialisées . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
7.2.1 Pour les nombres entiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
7.2.2 Pour les nombres flottants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
7.2.3 Initialisation de tableaux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
[Link] Initialisation d’un tableau avec plusieurs valeurs . . . . . . . . . . . . . 36
[Link] Initialisation d’un tableau avec une seule valeur . . . . . . . . . . . . . 37
7.2.4 Initialisation de chaînes de caractères . . . . . . . . . . . . . . . . . . . . . . . . 37
7.3 Déplacement de données . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
7.4 Manipulation de données de la pile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
7.5 MOV en détail . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38

8 Les opérations sur les données 39


8.1 Additions et Soustractions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
8.2 Multiplication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
8.3 Division . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
8.4 Incrémentation et décrémentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
8.5 Changement de signe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
8.6 Les opérations logiques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
8.7 Décalages et rotations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
8.7.1 Décalage logique à gauche . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
8.7.2 Décalage logique à droite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
8.7.3 Décalage arithmétique à droite . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
8.7.4 Rotation à droite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
8.7.5 Rotation à gauche . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
8.7.6 Rotation à droite à travers la retenue . . . . . . . . . . . . . . . . . . . . . . . . . 45
8.7.7 Rotation à gauche à travers la retenue . . . . . . . . . . . . . . . . . . . . . . . . 46

3
9 Les chaînes de caractères 47
9.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
9.2 Transfert . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
9.3 Comparaison . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
9.4 Répéter les instructions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49

10 Boucles et sauts 50
10.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
10.2 Les sauts inconditionnels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
10.3 Les sauts conditionnels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
10.4 Tableau des instructions de sauts conditionnels . . . . . . . . . . . . . . . . . . . . . . . 51
10.5 Boucles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
10.5.1 Exemple de programme utilisant une instruction de saut . . . . . . . . . . . . . . 52
10.5.2 Définition de ces instructions destinées aux boucles. . . . . . . . . . . . . . . . . 53

11 Blocs de répétitions et les Macros 54


11.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
11.2 Blocs de répétition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
11.2.1 Combinaison de REPT et du signe = . . . . . . . . . . . . . . . . . . . . . . . . 54
11.3 Les Blocs de répétition et les paramètres variables . . . . . . . . . . . . . . . . . . . . . . 55
11.4 Les Macros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
11.4.1 Principe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
11.4.2 Exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
11.4.3 Définition des labels dans les macros . . . . . . . . . . . . . . . . . . . . . . . . 56
11.5 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56

12 L’unité de virgule flottante : FPU 57


12.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
12.2 L’unité de virgule flottante : FPU . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
12.3 Les registres de la FPU . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
12.4 Définition de variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
12.5 Les instructions FPU . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
12.5.1 Le transfert de données . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
12.5.2 Les instructions arithmétiques . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
12.5.3 Les instructions spécialisées . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
12.5.4 Les instructions trigonométriques . . . . . . . . . . . . . . . . . . . . . . . . . . 60
12.5.5 Les instructions de constantes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
12.6 Exemple de programme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
12.7 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61

13 SIMD_MMX_SSE 63
13.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
13.2 MMX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
13.3 Les registres MMX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
13.4 Les instructions MMX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
13.5 Exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
13.6 Le SSE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
13.7 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65

14 Les Interruptions 66
14.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
14.2 Les interruptions matérielles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
14.2.1 Le PIC 8259 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
14.2.2 Les 2 PIC 8259 en cascade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67

4
14.2.3 L’IO_APIC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
14.3 Les interruptions logicielles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
14.3.1 Celles du DOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
14.3.2 Celles du BIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
14.3.3 Celles de Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
14.4 Les exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
14.4.1 Les fautes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
14.4.2 Les trappes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
14.4.3 Les arrêts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
14.5 La table des vecteurs d’interruption . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
14.6 Gestion des interruptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
14.6.1 Le RESET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
14.7 Interruption logicielle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
14.7.1 NMI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
14.7.2 INTR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
14.8 Le mode pas à pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
14.9 Le BIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
14.10Des exemples sous Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75

15 Le mode protégé 77
15.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
15.2 Quelques définitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
15.3 Les registres du 286 en mode protégé . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
15.4 La Gestion de la mémoire virtuelle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
15.4.1 Format d’une adresse virtuelle en mode protégé . . . . . . . . . . . . . . . . . . . 79
15.4.2 Les registres permettant la gestion de la mémoire virtuelle . . . . . . . . . . . . . 79
15.4.3 Taille de la mémoire virtuelle adressable par le 80286 . . . . . . . . . . . . . . . . 80
15.5 Les mécanismes de protection mémoire ou les Niveaux de privilège . . . . . . . . . . . . 80
15.6 Le changement de tâche . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
15.7 Les exceptions et les interruptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
15.8 Le mode Protégé des microprocesseurs 386 et 486 . . . . . . . . . . . . . . . . . . . . . . 82
15.8.1 Les registres des 386 et 486 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
15.8.2 La structure des descripteurs de segments . . . . . . . . . . . . . . . . . . . . . . 82
15.8.3 La pagination et la mémoire virtuelle . . . . . . . . . . . . . . . . . . . . . . . . 83
15.8.4 Des modes d’adressage plus souples . . . . . . . . . . . . . . . . . . . . . . . . . 83
15.9 Passer du mode Réel au mode protégé . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
15.10Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
15.11Post-Scriptum . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86

16 La Communication avec le Matériel 87


16.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
16.2 Accès aux ports d’entrée-sortie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
16.3 La syntaxe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
16.4 Les adresses des ports d’entrée-sortie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
16.5 Les droits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
16.6 Exemple de programme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
16.7 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93

5
Table des figures

2.1 Le premier PC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.2 Le 8086, le microprocesseur du premier PC . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.3 Les fonctions de traitement d’un ordinateur . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.4 Organisation logique d’un odinateur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

3.1 Le registre code condition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17


3.2 La segmentation mémoire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20

5.1 Le principe de la pile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28


5.2 La pile, transmission de valeurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29

6.1 Adressage indirect . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31


6.2 Adressage basé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
6.3 Adressage indexé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
6.4 Adressage Indexé, basé et direct . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33

7.1 Les déplacements possibles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38

8.1 Les additions possibles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40


8.2 Décalage logique à gauche . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
8.3 Décalage logique à droite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
8.4 Décalage arithmétique à droite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
8.5 Rotation à droite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
8.6 Rotation à gauche . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
8.7 Rotation à droite à travers la retenue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
8.8 Rotation à gauche à travers la retenue . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46

9.1 Manipulation de chaîne . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47

14.1 Les différents types interruptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66


14.2 Le contrôleur d’interruption 8259 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
14.3 Les contrôleurs d’interruption 8259 en cascade . . . . . . . . . . . . . . . . . . . . . . . 67
14.4 L’IO APIC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68

15.1 Le MSW . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
15.2 Le diagramme de répartition des niveaux de privilège . . . . . . . . . . . . . . . . . . . . 80
15.3 Les accès autorisés . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
15.4 Les accès interdits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
15.5 Les adresses virtuelles, linéaire et physique . . . . . . . . . . . . . . . . . . . . . . . . . 83
15.6 :Les modes d’adressage du 80386 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84

6
, ce cours a été écrit dans le but d’enseigner une matière qui évolue très vite même trop, mais
B ONJOUR
est fort nécessaire à la compréhension du fonctionnement de l’ordinateur. Il est évident que l’on ne
peut prétendre savoir programmer une machine ou demander à une machine d’exécuter une fonction, si on
ne sait pas ce dont elle est constituée et comment elle fonctionne.
Il est vrai que le contenu de ce cours est vaste, néanmoins il ne présente pas de difficulté majeure. La
plupart des mécanismes à comprendre sont simples et seront vu lors de travaux pratiques en salle machines.
Il existe de nombreux ouvrages sur l’architecture des ordinateurs, dont certains sont de vrais “presse
papier”1 . Pour ma part je vous conseille : Architecture et technologie des ordinateurs (3éme édition) de
Paolo Zanella et Yves Ligier aux éditions DUNOD (500 pages) que vous pouvez trouver aux bibliothèques
du Campus 3 et de science de l’université se trouvant sur le Campus 2.
Mais bien sûr, cela n’est que mon avis.

1 Ce cours si vous l’imprimez peut lui aussi servir de “presse papier”.

7
Première partie

Le Logiciel ou Software

8
Chapitre 1

Introduction

1.1 Introduction
nombreux programmeurs considèrent que le langage machine est un thème tabou et ils ont un peu
D E
raison. En effet, avec les outils de programmation actuels, il devient presque aberrant de vouloir
programmer en assembleur. Alors que faisons-nous ici me direz-vous. . .
Le but de ce cours n’est pas de vous apprendre à écrire des programmes complets en assembleur, mais
de savoir lire et modifier certaines parties, ainsi que de comprendre les mécanismes de fonctionnement de
la machine. Il est très difficile de comparer la programmation en langage machine à celle réalisée sous
un des langages évolués connus comme PASCAL ou C. Ces derniers sont toujours axés sur la résolution
d’un certain type de problèmes. Par exemple COBOL est un langage de programmation adapté à la gestion,
C à la gestion de processus industriels et de systèmes d’exploitation comme UNIX. L’étude du langage
d’assemblage sera faite autour des microprocesseurs de la famille iAPX86 du constructeur Intel R .

1.2 Définition d’un langage machine


Turing est un des créateurs des ordinateurs contemporains. Il s’agit d’un mathématicien anglais
A LAN
qui, dans les années 50 désigna par “computing”, le fait de procéder à des calculs au moyen de
machines. En fait, un ordinateur ne fait que des calculs, tout problème se résout au moyen de l’addition,
des deux opérations logiques ET, et OU, ainsi que de la négation NON. Cette tâche est réalisée par le CPU
(Central Processor Unit), appelée UC (Unité Centrale). Pour travailler avec un ordinateur, il faut pouvoir
communiquer avec le microprocesseur 1. A l’évidence, la communication sera codifiée, il s’agira donc
d’un langage. Par exemple, l’instruction « additionner » existe, c’est certain, mais il est nécessaire de la
formuler correctement. Le microprocesseur ne sait pas ce qu’est un mot ou une lettre, le seul langage qu’il
“comprend”, est constitué de nombres compris entre 00 et F Fh ou 0000 0000 et 1111 11112 L”instruction
83 signifiant “additionner” n’a rien d’une évidence, aussi la programmation au moyen de ces valeurs est
complexe et difficilement compréhensible. c’est pour cette raison que les concepteurs se sont mis d’accord
sur des abréviations pour les instructions, donc pour les nombres.
Exemple
– add signifie “additionner”
– jmp signifie “sauter” etc. . .
Ces abréviations se nomment “codes mnémoniques ” ou “mnémoniques” tout simplement. Un programme
composé de tels mnémoniques, est appelé programme en langage d’assemblage et est traduit en langage
machine par un programme que l’on nomme assembleur. Plus un langage est près du système, plus il est
facile de traduire ses commandes en instructions machine. Il existe deux méthodes pour traduire un tel
programme :
1 Je n’aime pas les termes CPU et UC, car je pense qu’ils peuvent induire le lecteur en erreur et confondre UC avec les termes Unité

de commande et/ou Unité Centrale. Je préfère donc utiliser le terme microprocesseur, chose que je vais faire à partir de maintenant.

9
– celle de l’interpréteur et
– celle du compilateur.
Ces deux « transcripteurs » ont chacun leurs avantages et leurs inconvénients.

1.3 L’interpréteur
de l’exécution d’un programme, un interpréteur l’analyse instruction par instruction, exécute cha-
L ORS
cune d’elles, gère la mémoire, les variables, etc. . .
L’avantage d’un interpréteur est qu’il permet un gain de temps pendant la phase de développement d’un
programme puisque nous n’avons pas à transcrire préalablement les codes source (compilation etc. . . ).
L’inconvénient est la lenteur d’exécution.

1.4 Le compilateur
d’une compilation, le programme source est traduit en langage machine avant exécution, ce n’est
L ORS
qu’une fois cela fait qu’il pourra être exécuté par le microprocesseur. L’avantage d’un programme
compilé est qu’il est plus rapide d’exécution que le même, interprété. L’inconvénient est que pour toute
modification du programme, tout ou une partie doit à nouveau être compilé, ce qui d’une part prend beau-
coup de temps, et d’autre part est “usant” pour le programmeur.

1.5 Le langage d’assemblage


dépend de l’architecture machine, c’est-à-dire du type de microprocesseur que l’on utilise, et du sys-
I L
tème d’exploitation aussi, contrairement aux langages évolués qui sont indépendant de la machine phy-
sique mais quand même tributaire du système d’exploitation2.
Exemple : le célèbre programme "Hello World" écrit en langage C donne
1
2 /*Hello_world.c*/
3
4 int main() {
5
6 printf(" Hello world \n ") ;
7
8 }
En le traduisant ce programme source du langage C en langage d’assemblage de différentes architec-
tures de microprocesseurs, cela donne :

1.5.1 Pour l’architecture de type x86


Voici deux codes sources, pour vous montrer qu’il existe les deux syntaxes différentes :
1. La syntaxe AT&T R ,
2. La syntaxe Intel R .
Par défaut , les outils de binutils sous Linux génère du code avec la syntaxe AT&T R , si vous voulez générer
du code avec la syntaxe Intel R vous devez ajouter l’option -masm=intel aux commandes as et gcc.
2 Seul à ma connaissance, le langage JAVA permet de ne pas tenir compte de l’architecture machine et du système d’exploitation.

10
.file "hello_world.c" .file "hello_world.c"
.section .rodata .intel_syntax
.LC0: .section .rodata
.string " Hello world \n " .LC0:
.text .string " Hello world \n "
.globl main .text
.type main, @function .globl main
main: .type main, @function
pushl %ebp main:
movl %esp, %ebp push %ebp
subl $8, %esp mov %ebp, %esp
andl $-16, %esp sub %esp, 8
movl $0, %eax and %esp, -16
subl %eax, %esp mov %eax, 0
subl $12, %esp sub %esp, %eax
pushl $.LC0 sub %esp, 12
call printf push OFFSET FLAT:.LC0
addl $16, %esp call printf
leave add %esp, 16
ret leave
.size main, .-main ret
.section .size main, .-main
.[Link]-stack,"",@progbits .section
.ident .[Link]-stack,"",@progbits
"GCC: (GNU) 3.3.2 20031022" .ident
"GCC: (GNU) 3.3.2 20031022"

1.5.2 Pour l’architecture de type alpha


1 .ugen
2 .verstamp 3 11
3 .data
4 .align 3
5 .align 0
6 $$8:
7 .ascii "Hello World\X00"
8 .text
9 .align 4
10 .file 2 "hello.c"
11 .globl main
12 .loc 2 4
13 # 1 #include <stdio.h>
14 # 2
15 # 3 void main()
16 # 4 {
17 .ent main 2
18 main:
19 .option O1
20 ldgp $gp, 0($27)
21 lda $sp, -16($sp)
22 stq $26, 0($sp)
23 .mask 0x04000000, -16
24 .frame $sp, 16, $26, 0
25 .prologue 1

11
26 .loc 2 4
27
28 .loc 2 5
29 # 5 printf("Hello World");
30 lda $16, $$8
31 .livereg 0x0001C002,0x00000000
32 jsr $26, printf
33 ldgp $gp, 0($26)
34 .loc 2 6
35 # 6 }
36 .livereg 0x007F0002,0x3FC00000
37 ldq $26, 0($sp)
38 lda $sp, 16($sp)
39 ret $31, ($26), 1
40 .end main

1.5.3 Pour l’architecture de type sparc


1 .file "hello.c"
2 gcc2_compiled.:
3 .section ".rodata"
4 .align 8
5 .LLC0:
6 .asciz "Hello World"
7 .section ".text"
8 .align 4
9 .global main
10 .type main,#function
11 .proc 020
12 main:
13 !#PROLOGUE# 0
14 save %sp,-112,%sp
15 !#PROLOGUE# 1
16 sethi %hi(.LLC0),%o1
17 or %o1,%lo(.LLC0),%o0
18 call printf,0
19 nop
20 .LL1:
21 ret
22 restore
23 .LLfe1:
24 .size main,.LLfe1-main
25 .ident "GCC: (GNU) [Link].f.1"
Vous remarquez rapidement après la lecture des trois codes précédents, qu’il est plus “facile” de pro-
grammer en langage C qu’en langage d’assemblage. Mais vous allez voir au fur et à mesure des travaux
pratiques, que de connaître le microprocesseur permet d’écrire des applications plus performantes, ce qui
est la même chose pour l’étude du Système d’Exploitation. Dans ce cours, nous allons étudier les méca-
nismes principaux d’un microprocesseur et d’un ordinateur en s’aidant d’exemples sur une architecture de
type x686.
Le but n’est pas de savoir programmer en assembleur x686, mais de comprendre certains mécanismes.
Toutefois, vous devrez être capable d’analyser un programme en langage d’assemblage, de comprendre ce
qu’il fait et aussi de modifier une petite partie de son code.

12
Chapitre 2

Architecture d’un ordinateur de type


PC

PC1 est un micro-ordinateur familial, PC veut dire Personnal Computer, l’origine de cette appelation
L E
vient de la société IBM R qui a sorti cet ordinateur en 1983 en ayant comme ambition qu’il “débarque”
dans chaque foyer2.
Pour l’époque3 c’était une machine révolutionnaire, car elle intégrait les mêmes fonctions que les or-
dinateurs de cette même époque, à savoir, un lecteur de disquette, mais surtout un disque dur de 10 mega-
Octets...
Voici les photos des ancêtres...

F IG . 2.1 – Le premier PC

F IG . 2.2 – Le 8086, le microprocesseur du premier PC

1 C’est le type de machine le plus répandu, qui possède un mac, un atari parmi vous ?
2 Andy Groove le fondateur de Intel a même prédit que le PC remplacerait la télévision. . .
Tous à vos lecteur de DVD :)
3 Je vieillis...

13
2.1 Schéma général des fonctions de traitement
figure ci-dessous illustre cet organisation logique.
L A

F IG . 2.3 – Les fonctions de traitement d’un ordinateur

2.2 Organisation logique d’un ordinateur


figure ci-dessous illustre cet organisation logique.
L A

F IG . 2.4 – Organisation logique d’un odinateur

2.2.1 La mémoire
Elle a pour rôle
– d’enregistrer les informations,
– de les restituer sur demande,
– de les conserver jusqu’à ce qu’on les efface.
C’est un dispositif organisé en cellules élémentaires (que nous appellerons mot mémoire) pouvant contenir
chacune une valeur dont la taille est limitée par le constructeur.
Chacune de ces cases est repérée par un numéro d’ordre que l’on appelle : adresse. La mémoire est
caractérisée par :
– Sa capacité de stockage, le plus souvent exprimée en “caractères” alphanumériques. Cette capacité
peut varier de quelques milliers à plusieurs millions voir milliard d’ici peu.
– Son temps d’accès (de l’ordre de la ns)
– La longueur du “mot mémoire" exprimée en Bits (machines de 8, 16, 32 ou 64 bits voire 128 bits).

14
2.2.2 L’organe d’entrée
Il a pour rôle de prendre, sur ordre de l’organe de commande, les données qu’on lui présente sur un
support extérieur clavier, souris, lecture disque. . . et de les placer en mémoire.

2.2.3 Le bloc de calcul


On le nomme aussi Unité Arithmétique et Logique (UAL), il contient les opérateurs capables d’effectuer
les opérations élémentaires : addition, multiplication,... Nous les considérons comme des “boites noires”4
qui agissent sur les termes se présentant à leur entrée et donnent en sortie, les résultats correspondants.

2.2.4 L’organe de sortie


Il joue le rôle symétrique de celui de l’organe d’entrée, il prend les résultats en mémoire et les restitue
sous forme utilisable par le demandeur.

2.2.5 L’organe de commande


Il dirige l’ensemble de ces organes ainsi que le cheminement des informations.

4 Boîtes noires que nous avons un peu étudiées lors de la partie intitulée : Hardware.

15
Chapitre 3

Organisation d’un PC

3.1 Le Microprocesseur
PCs sont conçus autour des microprocesseurs de la famille iAPX86 de Intel R , 8086, 8088, 80286,
L ES
80386 ,80486, Pentium R , Pentium PRO R , P2, P3 et P4 pour les derniers.
Il existe d’autres fabricants de microprocesseurs pouvant être utilisés à l’intérieur d’un ordinateur de
type PC, on peut citer AMD R , Cyrix R . . .
Ce cours est basé sur les microprocesseurs de type iAPX386, car au début il n’y avait que cela et que
le département informatique ne dispose que de machine avec cette architecture.

3.2 La Mémoire
microprocesseur 8086 peut adresser 1 Mega-octet de mémoire soit plus précisément 220 cellules de 8
L E
bits. Les microprocesseurs suivants ont des capacités bien plus importantes.

µP Espace adressable Bus de données Bus d’adresses Fréquence1


8086 1 Mega-octet 16 bits 19 fils 4,77 MHz
80286 16 Mega-octet 16 bits 24 fils 6 MHz
80386 4048 Mega-octet 32 bits 30 fils 16 MHz
80486 4048 Mega-octet 32 bits 30 fils 33 MHz
Pentium 4048 Mega-octet 32 bits 30 fils 60 MHz
Pentium Pro 4048 Mega-octet 64 bits 30 fils 200 MHz
P2 4048 Mega-octet 64 bits 30 fils 300 MHz
P3 4048 Mega-octet 64 bits 30 fils 400 MHz
P4 4048 Mega-octet 64 bits x2 30 fils 3+ MHz

Rappel : un Octet comprend 8 bits. Un octet peut contenir une valeur entière comprise entre 0 et 255.
On appelle cet octet un byte que l’on déclarera en assembleur par la directive
.byte
Deux octets réunis peuvent contenir une valeur entière de 0 à 65535, cela s’appelle un demi-mot ou half-
word que l’on déclarera par la directive
.hword
Quatre octets permettent de représenter une valeur entière de 0 à 4 294 967 295 ou une valeur à virgule
flottante dite simple précision. On appelle ces 4 octets un mot ou word que l’on déclarera par la directive
.long ou .int

16
Huit octets permettent de représenter une valeur entière de 0 à 18 446 744 073 709 551 616. On appelle
ces 8 octets un double-mot ou double-word que l’on déclarera par la directive
.quad
Pour les nombres à virgule flottante dite à simple précision dit aussi double mots que l’on déclarera par la
directive
.float ou .single

3.3 Registres
microprocesseur 8086 dispose comme tous les autres microprocesseurs, d’un système de stockage
L E
très rapide, les registres. Ce sont des mémoires internes au microprocesseur, ils sont classés en cinq
catégories
– Le registre des flags ou des indicateurs ou registre “Code Condition”.
– Les huit registres d’usage général.
– Le registre pointeur d’instructions.
– Les quatre registres de segment.
Le tableau ci-dessous donne leurs noms et définitions

16 bits 16 bits
16 bits 8 bits 8 bits
AX AH AL Accumulateur CS Segment de code
BX BH BL Base DS Segment de données
CX CH CL Compteur ES Extra segment
DX DH DL Données SS Segment de pile

SP Pointeur de pile IP Pointeur d’instructions


BP Pointeur de base
SI Index source FLAG Registre de flag
DI index destination

Le registre d’état est un registre 16 bits qui contient les informations sur :
– l’état général du microprocesseur 8086,
– le compte-rendu des instructions qui viennent de s’exécuter.
Ses 16 bits sont appelés des bits indicateurs et leur définition est
– O = de débordement (Overflow)
– D = de sens (Direction)
– I = de masquage des interruptions (Interrupt)
– T = de trappe de débogage (Trap)
– S = de signe (Sign)
– Z = de zéro (Zero)
– A = de retenue auxiliaire (Auxiliary carry)
– P = de parité (Parity)
– C = de retenue (Carry)
La figure ci-dessous donne l’organisation des bits du registre d’état

F IG . 3.1 – Le registre code condition

Remarques : Il est bon d’utiliser les registres correspondant au travail que l’on désire réaliser.

17
3.3.1 Registres de travail
Ils sont au nombre de 9, certains sont directement utilisables par le programmeur, d’autres non.
AX : Accumulateur utilisé pour les opérations arithmétiques.
BX : Base pour les adressages
CX : Compteur pour le comptage
DX : Data pour les données Registres d’offset :
SI : Source Index utilisé lors d’opérations sur chaînes de caractères, associé à DS.
DI : Destination Index utilisé lors d’opérations sur les chaînes de caractères, associé à DS si utilisé
comme index et à ES lors de manipulation de chaînes.
IP : Instruction Pointer associé à CS, il indique la prochaine instruction à exécuter, et ne peut être
modifié par le programmeur. Seul le microprocesseur peut le modifier et le fait à chaque exécution d’une
instruction.
BP : Base Pointer associé à SS pour accéder aux données de la pile lors d’appels d’un sous-programme.
SP : Stack Pointer associé à SS, il indique l’adresse du dernier élément de la pile.

3.3.2 Registres de segment


Ils sont au nombre de 4 pour le microprocesseur 8086.
CS : Code Segment il contient l’adresse du segment de la mémoire de programme
DS : Data Segment il contient l’adresse du segment de mémoire de données
SS : Stack Segment il contient l’adresse du segment de mémoire de la pile
ES : Extra Segment segment supplémentaire pour adresser des données.
Les registres de segment implicitement associés aux registres du 8086

Registre Segment associé Situation


IP CS Toujours
BX DS Si utilisé comme base
SI DS Si utilisé comme index
DI DS Si utilisé comme index
DI ES Si utilisé comme destination
SP SS Toutes les opérations de pile
BP SS Si utilisé comme base

Le microprocesseur accède beaucoup plus rapidement à ses propres registres qu’à la mémoire exté-
rieure. Lorsqu’il adresse une case mémoire, il utilise les deux bus de données et d’adresses pour transférer
les informations. C’est inutile lorsqu’il s’agit de ses propres registres, ceux-ci se trouvant dans le processeur
même. Cet avantage est aussi utilisé pour la mémoire cache de 1er niveau2.

3.3.3 Améliorations des registres du 80286


Ce microprocesseur possède les mêmes registres que le 8086, seul le registre de drapeau diffère, afin
de supporter de nouvelles fonctionnalités pour le mode protégé3 .

3.3.4 Améliorations des registres du 80386 et 486


Ils possèdent un jeu de registres beaucoup plus étendu, conçu pour supporter les opérations en 32 bits
et ses nouveaux modes de fonctionnement. Les registres généraux, base, index, de drapeaux et le pointer
d’instructions peuvent maintenant être adressés sur 32 bits (au lieur de 16 bits pour les prédécésseurs).
Les registres de segment ont toujours une taille de 16 bits, mais deux registres FS et GS ont été ajoutés à
l’usage des programmes. Le jeu de registres du 80386 est un sur ensemble et est compatible avec celui du
8086. Les programmes écrit pour le 8086 et le 80286 fonctionnent donc aussi bien sur le 80386. Quand
2 Voir le chapitre initulé Mémoire Câche de la partie Hardware
3 Voir le chapitre initulé Mode protégé

18
un registre présent sur le 8086 peut être utilisé en version 32 bits, on y accède par un préfixe E (comme
Extended ou Etendu).

3.3.5 Améliorations des registres depuis le P2


Depuis quelques années, les microprocesseurs se trouvant dans les PC se sont munis de nouveaux
registres pour les instructions de types SIMD. Ce chapitre ne traite pas de ces registres, je vous invite à
aller lire le chapitre intitulé les instructions SIMD.

3.4 Les registres généraux des microprocesseurs x386 et plus


tableau ci-dessous montre la majeure partie des registres du microprocesseur 80 386. Il manque les
L E
registres dits spécialisés dont on ne se servira pas dans les différents Tp.
Noms des reg. 8 bits 16 bits 8 bits
Numéro des bits 31 ⇐⇒ 16 15 ⇐⇒ 8 7 ⇐⇒ 0

Usage général Noms des reg. 32 bits


Accumulateur EAX AH AX AL
Base EBX BH BX BL
Compteur ECX CH CX CL
Données EDX DH DX DL

Index 31 ⇐⇒ 16 15 ⇐⇒ 0
source ESI SI
destination EDI DI

Pointeur 31 ⇐⇒ 16 15 ⇐⇒ 0
de base EBP BP
de pile ESP SP
d’instruction EIP

Segment Registre 16 bits 15 ⇐⇒ 0


Code CS
Données DS
Extra ES
Données FS
Données GS
Pile SS

Drapeau EFLAGS 31 ⇐⇒ 0
Remarque : Il existe de nombreux autres registres tels
– les registres de débogage.
– les registres d’adressage.
– les registres de la FPU.
– les registres pour les instructions de type SIMD etc. . . 4

4 Nous verrons les registres de la FPU et de type SIMD dans les chapitres intitulés : L’unité de virgule flottante et La programmation

SIMD

19
3.5 Segmentation mémoire
microprocesseur 8086 est en mesure d’adresser 1 méga-Octets de mémoire. Il est donc nécessaire
L E
de disposer de 20 bits pour pouvoir adresser un emplacement de cette mémoire.
Les registres 16 bits ne suffisent donc pas à mémoriser les adresses. On utilise alors la combinaison
d’un registre de segment5 et d’un registre de déplacement ou d’offset. On adresse ainsi la mémoire avec
deux valeurs, une valeur de segment et une valeur de déplacement ou d’offset. La valeur du segment est
multipliée par 16 (par décalage de 4 positions binaires). On a ainsi une valeur sur 20 bits dont les quatre
bits de poids faibles sont nuls, il ne reste plus qu’à effectuer un déplacement de 0 à 65 535, possible avec
la valeur d’offset (correspondant à un déplacement de 64 Kilo-Octets).
La figure ci-dessous illustre ce principe.

F IG . 3.2 – La segmentation mémoire

Remarque : Pour les microprocesseurs à partir du 80 386, la gestion de la mémoire n’est plus du tout
la même. Nous verrons comment cela est fait dans le cours intitulé le Mode Protégé.
Autre remarque : Seule la famille des microprocesseurs iAPX utilise ce principe d’adressage segmenté.
Les autres utilisent l’adressage linéaire, car ils disposent de registres de taille suffisante.

5 Tout la dénomination de segmentation mémoire.

20
Chapitre 4

Structure d’un programme en langage


d’assemblage x386.

allons nous intéresser à la syntaxe A&T et non à la syntaxe Intel.


N OUS

4.1 Exemple de programme


premier programme a une longue "préhistoire". . .
C E

1 .text
2 .align 4
3 .data
4 Question:
5 .ascii "Avez-vous passe un bon week-end (O/N) ? \0"
6 Reponse1:
7 .ascii "\12Dommage pour vous ! J’’en suis navré!. \12\0"
8 Reponse2:
9 .ascii "\12Je suis content pour vous ! \12\0"
10 .global main
11 main:
12 pushl %ebp
13 movl %esp,%ebp
14
15 pushl $Question
16 call puts
17 addl $4,%esp
18
19 call getchar
20 cmpb $111,%al
21 je Oui
22
23 pushl $Reponse1
24 call puts
25 addl $4,%esp
26 jmp fin
27
28 Oui:

21
29 pushl $Reponse2
30 call puts
31 addl $4,%esp
32
33 fin:
34 movl %ebp,%esp
35 popl %ebp
36 ret
Pour vous montrez rapidement la différence aves la syntaxe Intel. Voici le même programme réalisant
les mêmes opérations, mais sous DOS1 .
Pour annecdote, ce programme est l’ancêtre du précédent et me servait lorsque ce cours était fait sous
le système d’exploitation DOS.
1 DOSSEG
2 .MODEL SMALL
3 .DATA
4 Question DB ’Avez-vous passà c un bon week-end (O/N) ? $’
5 Reponse1 DB 13,10
6 DB ’Dommage pour vous ! J’’en suis navrà c !’,13,10,’$’
7 Reponse2 DB 13,10
8 DB ’Je suis content pour vous !’,13,10,’$’
9 .CODE
10 MOV AX,@Data
11 MOV DS,AX
12 MOV DX,OFFSET Question
13 MOV AH,9
14 INT 21H
15 MOV AH,1
16 INT 21H
17 CMP AL,’o’
18 JZ Oui
19 CMP AL,’O’
20 JNZ Non
21 Oui:
22 MOV DX,OFFSET Reponse2
23 JMP Affiche
24 Non:
25 MOV DX,OFFSET Reponse1
26 Affiche:
27 MOV AH,9
28 INT 21H
29 MOV AH,4CH
30 INT 21H
31 END

1 Nous aurons l’occasion d’y revenir lors du TP intitulé : Un peu de DOS. . .

22
Vous pouvez remarquer que la syntaxe n’est pas la même et ce même programme, vous pouvez l’écrire
encore d’une autre façon, en utilisant la syntaxe A&T et en voulant l’exécuter sous DOS.
1 .text
2 .globl _main
3 .org 0x100
4 _main:
5 !Pose la question
6 mov dx,#Question
7 mov ah,#9
8 int 0x21
9
10 !Attend la saisie d’un caractère dont le code ASCII sera retournée dans AL
11 mov ah,#1
12 int 0x21
13
14 cmp al,#111 !est-ce o ?
15 je Oui !si oui, aller à l’etiquette oui
16
17 !c’est non
18 mov dx,#Reponse1
19 jmp Affiche
20
21 !c’est oui
22 Oui:
23 mov dx,#Reponse2
24
25 Affiche:
26 mov ah,#9
27 int 0x21
28
29 !Retour au dos
30 !mov ax,0x4c00
31 !int 0x21
32 ret
33
34 Question:
35 .ascii "Avez-vous passe un bon week-end (O/N) ?"
36 .byte 13,10
37 .ascii "$"
38
39 Reponse1:
40 .ascii "Dommage pour vous ! J’’en suis navre!"
41 .byte 13,10
42 .ascii "$"
43 Reponse2:
44 .ascii "Je suis content pour vous ! "
45 .byte 13,10
46 .ascii "$"
47
Nous nous contenterons dans un premier temps d’expliquer la syntaxe AT&T pour des programmes
devant être exécutés sous le système d’exploitation LINUX.

23
4.2 Composition d’une ligne de code
ligne de code a la forme :
U NE

<label> <instruction/directive> <opérande> <#commentaire> <\>


– <label> est un nom symbolique facultatif
– <instruction/directive> symbole prédéfini de directive ou une mnémonique d’instruction
– <opérande> combinaison de constantes, références mémoires, registres ou chaînes de texte
– <commentaire> optionnel, il sert à commenter le programme, il doit être précédé du caractère dièse
# ou point-virgule ;
– <\> indique que l’instruction se poursuit à la ligne suivante. Il est souvent utilisé lors de définitions
de structures ou la déclaration de nombres ou de constantes.

4.3 Les directives d’assemblage


directives d’assemblage ne génèrent pas de code exécutable. Elles donnent des ordres (d’ou le terme
L ES
directive) à l’assembleur lors de la phase d’assemblage. Elles ne constituent pas non plus l’ossature
du programme.
Ces directives commencent toutes par le symbole . (point). Le reste est obligatoirement des lettres de
l’aphabet en minuscules.
Exemple
.ascii
.align 4
Il existe un grand nombre de directives d’assemblage.

4.3.1 Les directives de segmentation


.align 4
Directive permettant d’agencer les données en 4, 8 16 voir 32 octets selon le type de microprocesseur
utilisé.
.data
Identifie le début du segment de données du programme
.text
Identifie le début du segment de code du programme

4.3.2 Les directives de constantes


.byte 74, 0112, 0x4A, 0X4a, ’J, ’\J
Elles ont toutes la même valeur et occupent chacune un octet mémoire
.ascii "Ring the bell\7"
Une chaîne de caractères où chaque caractère occupe un octet mémoire
.octa 0x123456789abcdef 013456789ABCDEF
Un grand nombre sur 8 octets donc 64 bits
.float 0f-314159265358979323846264338327\
95028841971.693993751E-40
Un nombre flottant ici -PI. On remarque ici l’utilisation du caractère \ pour la continuation de ligne.
Voir le chapitre sur les données en mémoire.

24
4.4 Les labels
sont des noms permettant de se référer à des nombres, chaînes ou emplacements mémoire. Ils sont
C E
toujours précédés du caractère $.
Par exemple dans le programme que l’on vient de voir ci-dessus,
$QUESTION permet de se référer à la chaîne de caractères "Avez-vous .... (O/N) ? $"
$OUI permet de se référer à l’adresse mémoire qui traitera la répo nse affirmative.
Les labels peuvent être composés des caractères suivants :
– Les caractères de l’alphabet A à Z et a à z
– _ (souligné)
– . (point) mais pas en tant que premier caractère sinon l’assembleur va le considérer comme une
directive d’assemblage.
– Les chiffres 0 à 9 mais pas en tant que premier caractère sinon l’assembleur va le considérer comme
un nombre.
Les carcatères $ et ? ayant une signification spéciale ne pourront pas être utilisés comme des noms de
symbole. Un symbole ne peut être défini qu’une seule fois. Un label peut être seul sur une ligne, dans ce
cas il correspond à l’adresse de l’instruction ou directive suivante.
Exemple
Oui :
pourrait être placé en début de ligne suivante mais est placé à cet endroit afin de faciliter la lecture du
source. Il est interdit d’utiliser les mots réservés de l’assembleur, ainsi que les noms des registres du mi-
croprocesseur. Les labels, servant à référencer une adresse du programme où il faudra se brancher pour
exécuter une suite d’instructions, devront se terminer par le signe : (deux points).

4.5 Les instructions


lignes de code de langage d’assemblage suivantes :
L ES

addl $4,%esp
cmpb $111,%al
movl %ebp,%esp
sont des instructions mnémoniques correspondant au jeu d’instructions qu’est capable de réaliser le mi-
croprocesseur 80386. Les instructions mnémoniques sont remplacées par une instruction équivalente en
langage machine, et l’assembleur génère ainsi du code exécutable par le microprocesseur.
L’instruction movl est une instruction de déplacement de données sur 32 bits.
L’instruction addl est une instruction d’opération (addition) sur 32 bits.
L’instruction jmp est une instruction de branchement à une adresse etc. . .
Pour plus de renseignements concernant ces instructions se référer au chapitre sur les instructions.

4.6 Les opérandes


servent à indiquer quels sont les objets auxquels doivent s’appliquer les instructions ou les direc-
E LLES
tives. Il existe différentes sortes d’opérandes :
– Les opérandes registres : elles sont précédées du caractère % : %ah, %edx, et dépendent du type de
microprocesseur.
– Les opérandes constantes : elles sont précédés du caractère $ : $111, $4.
– Les opérandes d’expressions constantes : elles permettent d’expliciter le programme et sont rempla-
cées par leur valeur lors de l’assemblage (3*2).
– Les opérandes labels : elles indiquent une adresse mémoire par un nom $Réponse1
– Les opérandes d’adressage mémoire : movl %eax, (Valeur1) , ici le registre eax récupère la valeur
pointée par l’étiquette Valeur1

25
4.7 Les commentaires
n’ont pas d’effet sur le fonctionnement du programme, car l’assembleur les ignore. Ils sont là pour
I LS
faciliter la lecture du programme. Un commentaire peut commencer une ligne pour indiquer le fonc-
tionnement des lignes d’instructions suivantes, ou peut être en fin de ligne pour la commenter. Il ne faut
pas surcharger le source de commentaires, mais un programme dépourvu de commentaires est incompré-
hensible2 . Ils sont précédés obligatoirement par le caractère dièse #.

2 Commentaire ne veut pas dire redondant...

26
Chapitre 5

La pile

5.1 Introduction
pile est un lieu de stockage intermédiaire pour le microprocesseur et le programmeur qui désire
L A
stocker des valeurs de façon temporaire. Le terme pile (stack en anglais) décrit parfaitement le fonc-
tionnement de ce stockage. La procédure utilisé est désignée par l’acronyme LIFO ("Last In First out") ce
qui est inscrit en dernier sur la pile, en sort en premier. Comme les assiettes dans le placard de la cuisine
ou bien l’étudiant qui arrive en retard et qui veut partir en premier. . .
Remarque : la procédure inverse se nomme FIFO ("First in First out"), qui est une procédure moins
utilisée.
En règle générale, la pile occupe une zone mémoire distincte de la zone mémoire contenant le code
ou les données d’un programme. Il n’y a donc pas d’intersection avec le segment de données. Pour cette
raison, il existe également pour le segment de pile un registre spécifique.
Son nom est segment de pile ss (Stack Segment), il en désigne le début.
Comme pour les autres segments (Text et Data), il faut un pointeur. C’est le pointeur de pile sp pour le
microprocesseur 8086 et esp pour les autres.
La paire de registres ss :esp désigne toujours la prochaine adresse lue ou écrite.

5.2 Les instructions pushl et popl


deux instructions permettant de déposer et récupérer une valeur dans pile sont pushl et popl. L’ins-
L ES
truction pushl permet de déposer sur la pile le contenu de registres, de données, ou d’un emplacement
mémoire. On récupère les valeurs déposées à l’aide de l’instruction popl.
Remarque : Il n’est pas obligatoire de désigner le même registre pour popl que celui utilisé lors du
pushl.

5.3 Le principe
début du programme, le pointeur de pile (le registre esp) désigne l’extrémité inférieure de la pile.
A U
Lorsque l’on dépose une valeur sur la pile, la valeur du pointeur diminue.
0 movl $0x1234,%eax
1 pushl 0x5678 ; On dépose sur la pile.
2 pushl %eax ; On dépose sur la pile..
3 popl %ebx ; On retire de la pile.
4 pushl %eax ; On retire de la pile.

27
F IG . 5.1 – Le principe de la pile

On peut remarquer en lisant que le source du programme écrit en langage d’assemblage, qu’il n’y a pas
d’instruction qui change la valeur du registre pointeur de pile esp. Ce dernier à sa valeur qui augmente ou
diminue de 4 (4 * 8 bits = 32 bits) lorsque l’on dépile et empile.

5.4 L’appel d’une fonction


pile est très sollicitée lors de l’appel d’une fonction ou d’un sous-programme. Lors d’un appel, la
L A
valeur du registre d’instruction EIP est automatiquement déposée sur la pile du programme. De même
lors du retour d’une fonction ou d’un sous-programme, le registre d’instruction EIP est automatiquement
affecté de la valeur se trouvant au sommet de la pile.
Remarque : Nous verrons cela plus en détail lors du cours intitulé “Les sous-programmes” et lors du
Tp initulé : “Manipulation de la pile”.

5.5 La pile lors de la transmission de paramètres


pile est souvent utilisée pour transmettre des paramètres d’une fonction à une autre. Vous avez dû
L A
remarquer qu’en C une fonction peut appeler une autre fonction et lui passer plusieurs paramètres.
Ces paramètres sont transmis par l’intermédiaire de la pile, et cette fois-ci, pour plus de facilité, ce n’est
plus le registre pointeur de pile qui nous permet de récupérer ces valeurs, mais le registre de base bp pour
le 8086 et ebp pour les autres. C’est pour cette raison qu’une fonction en assembleur commence toujours
par la séquence d’instructions suivante :
1 pushl %ebp ; mémorise le ebp courant dans la pile
2 movl %esp, %ebp ; ebp pointe sur le même endroit que esp
et se termine toujours par la séquence d’instructions suivante :
3 movl %ebp,%esp ; récupère le esp d’origine
4 popl %ebp ; récupère le ebp d’origine
Remarque : ces deux dernières instructions peuvent être remplacées par l’instruction
leave

28
F IG . 5.2 – La pile, transmission de valeurs

Très important : Les paramètres transmis ne figurent pas avant mais après l’emplacement mémoire désigné
par le registre pointeur de base ebp. La pile récupère donc les paramètres passés à une fonction via la pile,
mais la valeur de retour doit être mise dans le registre EAX.

29
Chapitre 6

Modes d’adressage mémoire

6.1 Définition
l’on utilise une opérande mémoire, on doit spécifier l’adresse mémoire que l’on veut atteindre.
L ORSQUE
Les modes d’adressage représentent le chemin que l’on va emprunter pour aller chercher une donnée
ou stocker un résultat en mémoire.
Le microprocesseur 8086 sait désigner un emplacement mémoire selon les méthodes les plus variées.
Depuis la simple indication d’un offset ou l’exploitation du contenu d’un registre, jusqu’aux méthodes
d’adressage les plus complexes, dans lesquelles l’adresse est calculée en additionnant le contenu de plu-
sieurs registres à une valeur constante. Pratiquement toutes les méthodes possibles et imaginables sont
représentées. L’intérêt de tous ces modes d’adressage est de simplifier le travail du programmeur notam-
ment dans la manipulation de tableaux pluri-dimensionnels en Pascal et de pointeurs en C.
Le microprocesseur 8086 connaît en fait 19 modes d’adressage que l’on peut ramener à 6 mécanismes
fondamentaux.
– immédiat et direct.
– registre.
– indirect.
– indirect registre.
– indirect indexé.
– base indexé.
Les exemples utiliseront l’instruction mov qui est l’instruction qui permet le transfert des données.
Remarque : Les modes d’adressages expliqués ci-dessous ne sont qu’un aperçu des possibiltés du
microprocesseur 80386 utilisé en mode protégé, on peut tout imaginer et s’il fallait tous les expliquer, cela
dépasserait largement le but ce cours.

6.2 Adressage immédiat


’ EST le mode d’adressage le plus simple et le plus utilisé. Le contenu du registre est initialisé par une
C valeur immédiate (constante).
Registre ⇐ Valeur immédiate
Exemples :
1 movb $10,%ah ; Transfert de 8 bits.
2 movw $8A,%ebx ; Transfert de 16 bits.
3 movl $1234,%ecx ; Transfert de 32 bits.
Comme nous sommes en présence de microprocesseurs 32 bits, cette taille est maximale pour les registres.
Nous verrons lors du cours sur les instructions MMX, qu’il est possible de faire des échanges de données
sur 64 bits et même sur 128 bits (avec les instructions SSE).

30
6.3 Adressage indirect
E contenu d’un registre est initialisé par le contenu d’une zone mémoire.
L Registre⇐ Le contenu mémoire
L’image ci-dessous explique le principe.

F IG . 6.1 – Adressage indirect

Exemples :
1 Octet1 : .byte 10
2 Double_Octet2 : .word 0x1234
3 Quadruple_Octet3 : .long 0x12345678
4 movb Octet1,%ah ;Transfert de la mémoire vers un registre 8 bits.
5 movw %ax, Double_Octet2 ;Transfert d’un registre 16 bits vers la mémoire.
6 movl %eax, Quadruple_Octet3 ;Transfert d’un registre 32 bits vers la mémoire.

6.4 Adressage basé


mode d’adressage permet d’initialiser le contenu d’un registre avec la zone mémoire située à l’adresse
C E
%ds :(%ebx), avec (%ebx) qui représente le contenu de la mémoire dont l’adresse est dans le registre
ebx (pour l’offset), dans le segment désigné par le registre ds.
Registre⇐ (%ebx) dans de segment de données ds.
L’image ci-dessous explique le principe.

F IG . 6.2 – Adressage basé

Exemple 1 : Transfert de la donnée située en %ds :0000000A dans le registre eax.

31
1
2 movl $10,%ebx ; On place la valeur de l’offset dans le registre ebx
3 movl (%ebx),%eax ; Le registre eax est initialisé par le contenu de ds :0000000a.
Attention : Le registre eax ne vaut pas 10 ! ! !
Dans l’exemple qui suit, cela se complique un peu. . .
Exemple 2 : à l’étiquette Mot (adresse sur 32 bits), il y a une donnée sur 16 bits, on affecte la valeur
de l’offset au registre ebx et la donnée sur 16 bits au registre ax.
1 Mot : .word 1
2 movl %ebx, OFFSET Mot ; le registre ebx contient l’adresse de Mot dans le segment DS
3 movw (%ebx), %ax ; le registre ax contient la même valeur que Mot soit 1
Il s’agissait d’un adressage basé sur le registre de segment ds, mais on peut aussi le baser sur le registre de
segment ss. Dans ce cas, c’est le registre ebp qui va contenir l’offset.
Registre ⇐ (%ebp) dans le segment SS

6.5 Adressage indexé


mode d’adressage est utilisé pour manipuler les chaînes de caractères1 . Souvent basé sur les registres
C E
de segment DS et ES.
Registre ⇔ (%esi) ou
Registre ⇔ (%edi)
L’image ci-dessous explique le principe.

F IG . 6.3 – Adressage indexé

Exemple : Transfert de la donnée située en %ds :0000000A dans le registre eax.


1 movl $10,%esi
2 movw (%esi),%eax ; %al⇐ (%ds :%esi) et %ah⇐ (%ds :%esi + 1)

6.6 Les combinaisons


est possible de combiner les modes d’adressages précédents afin d’en obtenir des plus complexes.
I L

6.6.1 Adressage indexé et basé


Ce mode d’adressage utilise les modes d’adressages basé et indexé. Le registre est inialisé par la donnée
se trouvant à l’adresse contenue dans le registre de base (ebx ou ebp) plus le contenu du registre d’index
(esi ou edi) : adressage basé + indexé.
1 Nous verrons cela plus en détail et l’intérêt de ce mode d’adressage lors du cours sur la manipulation de chaînes de caractères.

32
Registre ⇐ (%ebx, %esi) ; basé sur le registre ds ⇔ Registre ⇐ (%ebx + %esi)
Registre ⇐ (%ebx, %edi) ; basé sur le registre ds ⇔ Registre ⇐ (%ebx + %edi)
Ce mode d’adressage utilise les registres ebx comme base, et esi ou edi comme index dans le segment
ds.
1 movl $2,%ebx
2 movl $10,%esi
3 movb (%ebx,%esi),%ah ;%ah ⇐ (%ds :%ebx + %esi) soit %ds :0000000C.
Lorsque la base est sur le registre de segment ss on utilise les registres ebp et esi ou edi
Registre⇐ (%ebp, %esi) ; basé sur le registre ss⇔ Registre ⇐ (%ebp + %esi)
Registre⇐ (%ebp, %edi) ; basé sur le registre ss⇔ Registre ⇐ (%ebp + %edi)

6.6.2 Adressage basé et déplacement direct ou immédiat


Ce mode d’adressage utilise les modes d’adressages basé et direct. Le registre est inialisé par la donnée
se trouvant à l’adresse contenue dans le registre de base (ebx ou ebp) plus la valeur se trouvant immédiate-
ment après : adressage basé + déplacement.
Registre ⇐ donnée(%ebx) ; basé sur le registre ds ⇔ Registre⇐ (%ebx + donnée)
Registre ⇐ donnée(%ebp) ; basé sur le registre ss ⇔ Registre⇐ (%ebp + donnée)

6.6.3 Adressage indexé et déplacement direct ou immédiat


Ce mode d’adressage utilise les modes d’adressages indexé et direct. Le registre est inialisé par la
donnée se trouvant à l’adresse contenue dans le registre d’index (esi ou edi) plus la valeur se trouvant
immédiatement après : adressage indexé + déplacement.
Registre ⇐ donnée(%esi) ; basé sur le registre ds ⇔ Registre ⇐ (%esi + donnée)
Registre ⇐ donnée(%edi) ; basé sur le registre ds ⇔ Registre ⇐ (%edi + donnée)

6.6.4 Adressage basé, indexé et déplacement direct ou immédiat.


C’est le mode d’adressage le plus complet, il permet de faire à peu près tout ce dont on a besoin. . .
L’image ci-dessous explique le principe.

F IG . 6.4 – Adressage Indexé, basé et direct

Registre ⇐ donnée(%ebx,%esi) ⇔ Registre ⇐ (%ebx + %esi + donnée) dans le segment DS


Registre ⇐ donnée(%ebx,%edi) ⇔ Registre ⇐ (%ebx + %edi + donnée) dans le segment DS
Registre ⇐ donnée(%ebp,%esi) ⇔ Registre ⇐ (%ebp + %esi + donnée) dans le segment SS
Registre ⇐ donnée(%ebp,%edi) ⇔ Registre ⇐ (%ebp + %edi + donnée) dans le segment SS

33
6.6.5 Remarques
On ne peut pas utiliser tous les registres en tant que registres d’adresse, mais uniquement les registres
ebx, esi, edi et ebp. Il est tout à fait possible d’en combiner deux, le microprocesseur additionne alors leur
contenu et utilise la somme résultante en tant qu’offset de la case mémoire à lire ou à écrire.
D’où les combinaisons suivantes
– (%ebx), (%esi), (%edi), (%ebp)
– (%edi + %ebx), (%esi + %ebx), (%edi + %ebp), (%esi + %ebp),
les combinaisons :
– edi avec esi, et
– ebp avec ebx
sont interdites.

6.6.6 Remarque 2, mode protégé


Depuis le 80386 et le mode protégé, n’importe quel registre général peut servir de base ou d’index. Un
multiplicateur d’échelle (1, 2, 4, ou 8) peut aussi être ajouté. Par exemple :
1 movl $2,%ebx
2 movl $4,%esi
3 movb 3(%ebx,%esi, 4),%ah ;%ah ⇐ (%ds :%ebx + 3 + 4*%esi) soit %ds :00000013 (adresse

6.7 Conclusion
ne faut pas essayer de retenir tous ces modes d’adressages. Les compilateurs qui traduisent des lan-
I L
gages évolués en langage d’assemblage les connaissent pour vous. Vous pourrez vous référer à ce cours
pendant les TP.

34
Chapitre 7

Données en mémoire

7.1 Base de calcul


est possible de définir la base avec laquelle on désire coder les nombres dans le source du programme
I L
écrit en langage d’assemblage. Cela peut être commode lorsque l’on doit faire des masques binaires ou
des opérations logiques. . .
Il est donc nécessaire de préciser à l’assembleur dans quelle base sont codés les nombres. Pour cela
chaque nombre devra être précédé d’un préfix indicateur.
Les bases possibles sont :
– Notation décimale : Par défaut l’assembleur fera les calculs en décimal donc movw $100,%cx signi-
fie que l’on initialise le registre CX à la valeur 100.

movw $100,%cx # initialise le registre CX à la valeur 100 en base 10...


– Notation binaire : Pour un nombre binaire il faut placer 0b devant le nombre

movw $0b1100100,%cx # initialise le registre CX à la valeur 100 en base 10...


– Notation octale : Pour un nombre en octal il faut placer un 0 devant le nombre

movw $0144,%cx # initialise le registre CX à la valeur 100 en base 10...


– Notation hexadécimale : Pour nombre en hexadécimal il faut placer un 0x devant le nombre

movw $0x64,%cx # initialise le registre CX à la valeur 100 en base 10...


Remarque : il est possible de faire commencer un nombre décimal par 0 (zéro), mais attention si votre
nombre ne contient que des chiffres strictement inférieurs à 8, ce nombre sera interprété par l’assembleur
comme un nombre codé en octal.

movw $0144,%cx # initialise le registre CX à la valeur 100 en base 10...


movw $0149,%cx # initialise le registre CX à la valeur 149 en base 10...

7.2 Données initialisées


7.2.1 Pour les nombres entiers
Malgré que la majorité des microprocesseurs actuels soient 32 bits voire 64 bits, il est possible d’avoir
des tailles de nombres entiers différentes de ces deux valeurs. Pour réaliser une opération dont la taille

35
des opérandes est inférieure à la taille des registres généraux du microprocesseur, cela ne pose aucun
problème. Il suffit de remplacer les bits de poids forts inutilisés par des 0 ou par le signe dans le cas d’une
opération signée. Pour réaliser une opération dont la taille des opérandes est supérieure à la taille des
registres généraux du microprocesseur, on découpe ces opérandes en blocs dont la taille vaut celle des
registres généraux du microprocesseur, et on se sert du bit carry pour les retenues (additions) et les reports
(soustractions).
– .byte ⇔ 1 octet
– .hword ou .short⇔ 2 octets⇔ un demi-mot, half-word
– .long ou .int ⇔ 4 octets ⇔ un mot de 32 bits par défaut1
– .quad⇔ 8 octets⇔ un mot de 64 bits
– .octa⇔ 16 octets⇔ un mot de 128 bits

7.2.2 Pour les nombres flottants


Il existe deux types de nombres flottants selon qu’ils soient simple ou double précision, donc 32 ou
64 bits. En général, les coprocesseurs mathématiques ou unité de virgule flottante (FPU) possèdent des
registres 80 bits qui permettent de gérer les deux types. 2
.float⇔ 4 octets, ce sont les nombres simple précision
.double⇔ 8 octets, ce sont les nombres double précision
Exemple :
1 .data
2 #Pour les nombres entiers
3 Octet :
4 .byte 0b10101010
5 Demi_mot :
6 .hword 0x1234
7 Mot :
8 .word 0x12345678
9 Double_mot :
10 .quad 0b100100011010001010110011110001001101010111100110111101111
11 Quadruple_mot :
12 .octa 0x123456789abcdef0123456789ABCDEF0
13 #Pour les nombres flottants
14 #Simple_précision
15 .float -3.1415926535
16 #ou
17 .single 0f-314159265358979323846264338327\
18 95028841971.693993751E-40 # Un nombre flottant ici -PI.
19 #Double_précision :
20 .double 0f+314159265358979323846264338327\
21 9502884197169399375105820974944592.230781640628620899862803481E-63

7.2.3 Initialisation de tableaux


[Link] Initialisation d’un tableau avec plusieurs valeurs
Exemple
Tableau : .byte 1,2,3,4,5,6,7,8,9,10
1 .int dépend de l’architecturedu microprocesseur. Cette valeur est relative à la taille des registres de calculs de l’Unité Arithmétique
et Logique.
2 Nous verrons lors du chapitre intitulé : Unité de virgule flottante cette notion de simple et double précision.

36
[Link] Initialisation d’un tableau avec une seule valeur
Exemple
Tableau : .space 4,25 # stocke 4 fois 25 à l’adresse Tableau

7.2.4 Initialisation de chaînes de caractères


Exemple
1 Chaine1 :
2 .ascii “Bonjour tout le monde\0”
3 Chaine2 :
4 .string “Une chaîne de caractère” # ajoute le caractère 0 à la fin automatiqueme

7.3 Déplacement de données


’ INSTRUCTION principale qui permet d’effectuer cette opération est l’instruction mov (abréviation de
L Move ). Cette instruction fait une copie de l’opérande source dans celle de destination.
1 movw $0, %ax # ax⇐ 0
2 movw (10), bx # bx⇐ %ds :(10)
3 movw %ax,%bx # bx⇐ ax=10

Résultat : les registres ax et bx contiennent tous les deux la valeur 10.


Sélection de la taille des données : Afin que l’assembleur puisse connaître la taille des données que l’on
désire manipuler, il faut ajouter les caractères
– b pour un byte ou octet, donc 8 bits
– w pour un word ou mot, donc 16 bits
– l pour un longword ou double-mots, donc 32 bits ou
– q pour un quad-word ou quadruple-mots, donc 64 bits
en suffixe des instructions.
Exemple :
1 movb $10,%al # Taille 1 octet
2 movw $10,%ax # Taille 2 octets
3 movl $10,%eax # Taille 4 octets
4 movq $10,%mm0 # Taille 8 octets (MMX)
5 movapd (64),%xmm0 # Taille 16 octets (SSE), depuis la mémoire seulement (pas de vale
Remarque : Avec les registres MMX3 l’assembleur est capable de déterminer la taille des données à
déplacer.

7.4 Manipulation de données de la pile


4

instructions pushl (Pousse) et popl (Tire) peuvent également déplacer des données.
1
L ES

movw $10,%ax
2 pushl %eax
3 popl %ebx
Résultat : Les registres ax et bx contiennent tous les deux la valeur 10.
3 Nous verrons plus loin dans ce cours à quoi correspondent ces registre MMX.
4 On pourra consulter le chapitre intitulé : La pile pour avoir plus informations sur le mécanisme de fonctionnement de la pile.

37
7.5 MOV en détail
les combinaisons de déplacement ne sont pas valides. Ainsi, il est impossible de copier di-
T OUTES
rectement une case mémoire dans une autre. On doit passer par un registre dans lequel on chargera
la donnée à copier, puis copier en mémoire la donnée à partir de ce registre. Il existe d’autres petites
contraintes : ainsi on peut charger dans les registres de segment le contenu d’un autre registre, mais pas une
constante.
La figure suivante expose les possibilités offertes par la commande mov.

F IG . 7.1 – Les déplacements possibles

Remarque : Pour les microprocesseurs 386 et suivants, il faut remplacer respectivement les registres
ax à bp par les registres eax à ebp.

38
Chapitre 8

Les opérations sur les données

8.1 Additions et Soustractions


instructions add et sub opèrent sur des opérandes de 8, 16 ou 32 bits. Pour travailler sur des nombres
L ES
de 64 bits il faudra utiliser les instructions adc et sbb. L’instruction adc ressemble à l’instruction add
sauf qu’elle tient compte de l’état de l’indicateur de retenue positionné par une addition précédente. A
chaque fois que l’on additionnera deux valeurs dépassant la taille d’un mot de 32 bits, l’on additionnera les
mots de poids faibles avec l’instruction add puis les mots de poids forts avec adc. On procèdera de même
avec les instructions de soustraction en utilisant les instructions sub et sbb.

1 .data
2 valeur1: .long 0x20
3 valeur2: .long 0x30
4 .text
5 .globl main
6 main:
7 pushl %ebp
8 movl %esp, %ebp
9
10 movl (valeur1), %eax # initialise eax a valeur1
11 addl (valeur2), %eax # ajoute valeur2 au registre eax
12
13 movl (valeur1), %eax # initialise eax a valeur1
14 subl (valeur2), %eax # ajoute valeur2 au registre eax
15
16 leave
17 ret

Le code en langage d’assemblage ci-dessous montre comment réaliser une addition de nombres entiers
de 64 bits à l’aide de registres de 32 bits.

1 .data
2 valeur1: .quad 0x1111111122222222
3 valeur2: .quad 0x33333333ffffffff
4 Total: .quad 0x0
5 .text
6 .globl main
7 main:

39
8 pushl %ebp
9 movl %esp, %ebp
10 pusha #sav tous les reg
11
12 # initialise eax avec les 4 octets de poids faibles de valeur1
13 movl (valeur1), %eax
14 # initialise ebx avec les 4 octets de poids forts de valeur1
15 movl (valeur1 + 4),%ebx
16 # initialise ecx avec les 4 octets de poids faibles de valeur2
17 movl (valeur2), %ecx
18 # initialise edx avec les 4 octets de poids forts de valeur2
19 movl (valeur2 + 4),%edx
20
21 addl %ecx, %eax #addition sans retenue des poids faibles
22 adcl %edx, %ebx #addition avec retenue des poids forts
23
24 movl %eax,(Total)
25 movl %ebx,(Total + 4)
26
27 popa #rec tous les reg
28 leave
29 ret

Le résultat de cette opération se trouve dans la juxtaposition des registres ebx :eax qui forme alors
l’équivalent d’un registre 64 bits.
L’instruction sbb fonctionne de la même manière que adc pour la soustraction. Il faudra faire attention à
ce que l’indicateur de retenue n’ait pas été altéré par une opération étrangère à l’addition ou à la soustraction
que l’on désire effectuer.
La figure suivante expose les possibilités offertes par l’instruction d’addition add.

F IG . 8.1 – Les additions possibles

On a bien sûr les mêmes possibilités avec l’instruction de soustraction sub, il suffit simplement de
changer le signe. . .

8.2 Multiplication
’ INSTRUCTION de multiplication mul permet de multiplier deux valeurs non signées 1 sur 8, 16 ou 32
L bits, le résultat est sur 16, 32 ou 64 bits.
– Multiplication de deux nombres de 8 bits : Un des facteurs est al, le résultat sera sur 16 bits dans ax.
1 On rappelle qu’un nombre signé est un nombre dont le bit de poids fort représente le signe. Ce qui permet d’avoir des nombres

positifs et aussi des nombres négatifs.

40
– Multiplication de deux nombres de 16 bits : Un des facteurs est ax, le résultat sera sur 32 bits dans
eax.
– Multiplication de deux nombres de 32 bits2 : Un des facteurs est eax, le résultat sera sur 64 bits dans
edx :eax.
1 .text
2 .globl main
3 main:
4 pushl %ebp
5 movl %esp, %ebp
6 pusha #sav tous les reg
7
8 xorl %eax,%eax
9 xorl %ebx,%ebx
10 xorl %edx,%edx
11 # Multiplication sur 8 bits -> AX
12 movb $55, %al
13 movb $77, %ah
14 mulb %ah
15
16 # Multiplication sur 16 bits -> EAX
17 movw $5555, %ax
18 movw $7777, %bx
19 mulw %bx
20
21 # Multiplication sur 32 bits -> EDX:EAX
22 movl $5555555, %eax
23 movl $7777777, %ebx
24 mull %ebx
25
26 popa #rec tous les reg
27 leave
28 ret
L’instruction imul permet de multiplier des nombres signés sur 8, 16 ou 32 bits.

8.3 Division
microprocesseur 80386 autorise la division d’un nombre de 64 bits par un de 32 bits, de 32 bits par
L E
un de 16 bits ou un de 16 bits par un de 8 bits. Mais à ces divisions il y a des restrictions.
– Division 64 bits par 32 bits : Le dividende se trouve dans la paire de registres edx :eax et le diviseur
sur 32 bits dans un registre à usage général ou sous forme d’une variable mémoire.
L’instruction div place le quotient et le reste sur 32 bits dans respectivement les registres eax et edx.
mov $0x64, %eax
mov $0x14, %edx ; chargement de 85899346020 dans edx :eax
mov $0x14, %ebx
div %ebx ⇒ ;edx=1 et eax=05
Ce qui donne 4 294 967 301 en décimal donc 10 0000005 en hexadécimal.
Dans les sources du noyau Linux, on trouve un programme 3 écrit en langage d’assemblage qui émule
une division d’un nombre entier de 64 bits par un autre nombre entier de 32 bits, alors que l’on ne dispose
que d’un microprocesseur 32 bits.
2 Avant le 80386, on disposait de microprocesseur 16 bits et l’on faisait des multplications sur 16 avec le résultat qui était stocké

dans dx :ax. . .
3 Vous pouvez trouver ce programme dans le répertoire

41
1 .file "div_small.S"
2 /*---------------------------------------------------------------------------+
3 | div_small.S |
4 | |
5 | Divide a 64 bit integer by a 32 bit integer & return remainder. |
6 | |
7 | Copyright (C) 1992,1995 |
8 | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
9 | Australia. E-mail billm@[Link] |
10 | |
11 | |
12 +---------------------------------------------------------------------------*/
13
14 /*---------------------------------------------------------------------------+
15 | unsigned long FPU_div_small(unsigned long long *x, unsigned long y) |
16 +---------------------------------------------------------------------------*/
17
18 #include "fpu_emu.h"
19
20 .text
21 ENTRY(FPU_div_small)
22 pushl %ebp
23 movl %esp,%ebp
24
25 pushl %esi
26
27 movl PARAM1,%esi /* pointer to num */
28 movl PARAM2,%ecx /* The denominator */
29
30 movl 4(%esi),%eax /* Get the current num msw */
31 xorl %edx,%edx
32 divl %ecx
33
34 movl %eax,4(%esi)
35
36 movl (%esi),%eax /* Get the num lsw */
37 divl %ecx
38
39 movl %eax,(%esi)
40
41 movl %edx,%eax /* Return the remainder in eax */
42
43 popl %esi
44
45 leave
46 ret
47

Dans le source de ce programme :


lsw signifie : Least Significant Word
msw signifie : Most Significant Word

/usr/src/V E R S I O N _ D U _ K E R N E L /arch/i386/math-emu/div_small.S

42
Remarque : Consulter les sources du noyau Linux apprend beaucoup de choses sur l’architecture d’un
ordinateur. . .
– Division 32 bits par 16 bits : Le dividende doit se trouver dans le registre eax et le diviseur sur 16
bits dans un registre à usage général ou sous forme d’une variable mémoire.
L’instruction div place le quotient et le reste sur 16 bits dans respectivement les registres dx et ax.
– Division 16 bits par 8 bits : Le dividende doit se trouver dans le registre ax et le diviseur sur 8 bits
dans un registre à usage général ou sous forme d’une variable mémoire.
L’instruction div place le quotient et le reste sur 8 bits dans respectivement les registres al et ah.
Remarque : Il ne faut pas que le diviseur soit nul, sinon il y aura une interruption N˚0 (division par 0) de
générée.4

8.4 Incrémentation et décrémentation


est fréquent d’avoir besoin d’ajouter ou de soustraire une unité à un nombre. On utilise alors les ins-
I L
tructions d’incrémentation inc ou de décrémentation dec qui sont exécutées plus rapidement que les
instructions addition add et de soustraction sub.

1 .text
2 .globl main
3 main:
4 pushl %ebp
5 movl %esp, %ebp
6 pusha #sav tous les reg
7
8 movl $9,%eax
9
10 # Incrementation EAX <- EAX + 1 + 256 + 1 + 1
11 incb %al
12 incb %ah
13 incw %ax
14 incl %eax
15
16 # Decrementation EAX <- EAX - 1 - 256 - 1 - 1
17 decb %al
18 decb %ah
19 decw %ax
20 decl %eax
21
22 popa #rec tous les reg
23 leave
24 ret

8.5 Changement de signe


’ INSTRUCTION neg permet d’inverser le signe du contenu d’un registre ou d’une variable mémoire.
L movl $2,%ax
neg %eax ⇒ ; ax = -2
4 Nous verrons ces problèmes d’interruption au chapitre intitulé : les interruptions.

43
8.6 Les opérations logiques
s’agit des opérateurs logiques and, or, xor et de not, qui permettent comme leur nom l’indique de réa-
I L
liser les opérations logiques de base. Ces instructions logiques permettent de réaliser des comparaisons.
Exemple
Pour savoir si deux nombres sont égaux on fait un ou-exclusif donc l’instruction xor et on test si le
résultat est nul. Si le test est positif, alors les deux nombres sont égaux sinon non.
Cet opérateur logique xor est aussi trés utilisé pour inverser les couleurs d’une image, donc en faire le
négatif.5
Exemple
1010 1010 ⊕ 1111 1111 ⇒ 0101 0101.
– L’instruction and permet d’isoler un bit ou de le forcer à zéro.
mov 0xbb,%al
and $0x80,%al ⇒ test du bit 7 à 1
– L’instruction or permet de forcer un bit à 1
mov 0x5b,%al
or $0x80,%al ⇒ positionne le MSB de al à 1
– L’instruction not permet d’inverser tous les bits de l’opérande comme s’il s’agissait d’un xor de
0xffff.

8.7 Décalages et rotations


8.7.1 Décalage logique à gauche
Il y a le décalage logique vers la gauche avec l’instruction shl. L’opération de décalage shl n’accepte
comme opérande que la valeur 1 sinon il faut passer par l’intermédiaire du registre cl pour indiquer le
nombre de décalages successifs à effectuer.
Les décalages à gauche sont souvent utilisés pour effectuer des multiplications par puissance de 2.
shl $1,%edx ⇒; edx = edx * 2
shl $1,%edx ⇒; edx = edx * 4
shl $1,%edx ⇒; edx = edx * 8
shl $1,%edx ⇒; edx = edx * 16
ou alors
mov cl,4
shl %cl,%edx ⇒ ; edx = edx * 16

F IG . 8.2 – Décalage logique à gauche

8.7.2 Décalage logique à droite


De même il y a le décalage logique vers la droite avec shr, identique à shl sauf que le décalage s’effectue
dans l’autre sens. Les décalages à droite sont souvent utilisés pour les divisions par puissances de 2 non
signées.
5 Une image est constitué de pixels qui chacun est codé sur un certain nombre de bit, on peut ainsi réaliser une opération logique.

44
F IG . 8.3 – Décalage logique à droite

8.7.3 Décalage arithmétique à droite


Il existe aussi le décalage arithmétique vers la droite avec sar, opération qui permet de garder le signe
de l’opérande ; utilisé pour les divisions signées par puissance de 2.

F IG . 8.4 – Décalage arithmétique à droite

8.7.4 Rotation à droite


Cette instruction ror ressemble à l’instruction shr en dehors du fait que le bit le moins significatif (LSB)
est réintroduit dans le bit le plus significatif (MSB) en l’envoyant également dans le bit de retenue.

F IG . 8.5 – Rotation à droite

8.7.5 Rotation à gauche


Il y a la rotation à gauche qui correspond à l’opération inverse de rol en décalant l’opérande de manière
circulaire de droite à gauche.

F IG . 8.6 – Rotation à gauche

8.7.6 Rotation à droite à travers la retenue


Cette instruction rcr s’effectue comme la rotation à droite mais cette fois en passant à travers la retenue.

F IG . 8.7 – Rotation à droite à travers la retenue

45
8.7.7 Rotation à gauche à travers la retenue
Cette instruction rcl est identique à l’opération rcr précédente mais dans l’autre sens.

F IG . 8.8 – Rotation à gauche à travers la retenue

46
Chapitre 9

Les chaînes de caractères

9.1 Introduction
la plupart des applications informatique, il y a de nombreuses manipulations sur les chaînes de
D ANS
caractères. On doit donc disposer de techniques rapides de transfert ou de comparaison de chaînes de
caractères.
On rappelle qu’une chaîne de caractères est une suite d’octets, de mots de 16 bits ou de mots de 32
bits selon le codage utilisé1 , rangés les uns à la suite des autres et ayant chacun une adresse propre. Dans
notre cas nous allons considérer que nous utilisons toujours le code ASCII donc chaque caractère n’occupe
qu’un octet en mémoire.
Dans les opérations décrites dans ce chapitre, interviennent toujours deux zones mémoire.
– La première est nommée : chaîne source.
– La seconde est nommée : chaîne destination.
La chaîne source doit toujours être pointée par le registre de segment de données ds et
La chaîne destination par le registre de segment de données es.

F IG . 9.1 – Manipulation de chaîne

Quelle que soit l’opération que l’on veut faire sur une ou deux chaînes de caractères, consultation,
modification, comparaison, elle est exécutée caractère par caractère. Il faut donc maintenir deux registres
d’index, un pour la chaîne source et un pour la chaîne destination permettant de connaître à tout moment
le remplissage ou la comparaison de chaque chaîne.
Les deux registres d’index que l’on utilise sont :
– Le registre d’index esi pour la chaîne source et
– Le registre d’index edi pour la chaîne destination.
Principe
On fait pointer respectivement les paires de registres ds :esi et/ou es :edi sur le premier caractère des
chaînes de caractères sur lesquelles on désire travailler. On exécute l’instruction nécessaire à notre travail,
ensuite il faut incrémenter ou décrémenter automatiquement les registres edi et/ou esi. Le terme auto-
matiquement veut dire que ce n’est pas au programmeur d’incrémenter ou décrémenter les deux registres
d’index, cela est fait automatiquement après l’opération de manipulation des chaînes de caractères.
Pour cela, il existe 2 instructions qui permettent de positionner un des bits du registres de flags 2 . Ces
instructions sont
1 Je vous invite à relire le chapitre intitulé le codage de l’information dans la partie Hardware.
2 Voir le chapitre intitulé Organisation d’un PC.

47
– cld (Clear Direction Flag) indique que les registres esi et edi sont automatiquement incrémentés
après une instruction de manipulation de chaîne.
– std (Set Direction Flag) indique que les registres esi et edi sont cette fois ci, automatiquement décré-
mentés toujours après une instruction de manipulation de chaîne.
Remarque : Ce sont des instructions de types implicites, elles n’ont pas besoin d’opérande.

9.2 Transfert
existe 3 types de transfert d’une chaîne de caractères.
I L
– Si on désire modifier une chaine de caractères et dans ce cas il faut charger les caractères dans un
registre du microprocesseur et on utilise alors les instructions
lodsb, lodsw et lodsl (Load String Byte, Word et Long).
Ces instructions chargent les registres al, ax ou eax avec un élément d’une chaîne pointée par ds :esi
(opérande source). Après l’opération, le registre d’index esi est automatiquement incrémenté ou dé-
crémenté de 1, 2 ou 4.

al, ax ou eax ⇐ [ds :esi) et esi = esi + 1 ou +2 ou + 4.

– Si on désire mémoriser le caractère qui vient d’être modifié dans sa chaîne de caractères d’origine
ou une autre, on utilise alors les instructions
stosb, stosw et stosl (Store String Byte, Word et Long), ces instructions chargent l’élément d’une
chaîne pointée par es :edi (opérande destination)avec le contenu des registres al, ax ou eax. Après
l’opération, le registre d’index edi est automatiquement incrémenté ou décrémenté de 1, 2 ou 4.

[es :edi) ⇐ al, ax ou eax et edi = edi + 1 ou +2 ou + 4.

– Si on désire deplacer une zone mémoire contenant une chaîne de caractères vers une autre zone mé-
moire et dans ce dernier cas, on utilise alors les instructions
movsb, movsw et movsl (Move String Byte, Word et Long), ces instructions transfèrent un octet ou un
mot de la zone mémoire pointée par ds :esi vers la zone mémoire pointée par es :edi, ces registres
doivent donc être correctement initialisés. Après l’opération, les registres d’index edi et esi sont au-
tomatiquement incrémentés ou décrémentés de 1, 2 ou 4.
Remarque : dans le cas de déplacement de zone mémoire, les registres al, ax ou eax ne sont pas
affectés !

[es :edi) ⇐ [ds : esi) et


edi = edi + 1 ou +2, esi = esi + 1 ou +2 ou + 4.

9.3 Comparaison
est trés intéressant de posséder des outils permettant de savoir si un caractère se trouve dans une chaîne
I L
de caractères ou bien de comparer deux chaînes de caractères. Pour cela on dispose de 2 types d’ins-
tructions de comparaison.

– Si on désire savoir si un caractère se trouve dans une chaîne de caractères, on utilise les instructions
scasb, scasw et scasl (Scan String Byte, Word et Long), ces instructions comparent un élément (un
octet, 2 octets ou un mot de 4 octets) d’une chaîne de caractères pointée par les registres es :edi avec
le contenu des registres al, ax ou eax. Ces instructions seront utilisées pour rechercher un caractère
dans une chaîne. Après l’opération, le registre d’index edi est automatiquement incrémenté ou dé-
crémenté de 1, 2 ou 4.

48
– Si on désire comparer deux chaînes de caractères, on utilise les instructions
cmpsb et cmpsw et cmpsl (Compare String Byte, Word et Long), ces instructions comparent un élé-
ment (un octet ou un mot) de deux chaînes de caractères, le premier étant pointé par ds :esi et le
second par es :edi. Ces instructions affectent les indicateurs du registre d’état du microprocesseur
pour indiquer le résultat de la comparaison. Après l’opération, les registres d’index edi et esi sont
automatiquement incrémentés ou décrémentés de 1, 2 ou 4.

9.4 Répéter les instructions


manipulation de chaînes de caractères engendre la répétition de la même exécution d’une instruc-
L A
tion. Il existe un ensemble de macro instructions qui ne sont pas dans le jeu d’instructions du mi-
croprocesseur, mais qui existent dans tous les assembleurs traitant le code en langage d’assemblage des
microprocesseurs de la famille iAPX86.
Ces instructions sont
rep,
repe,
repne.
Le mécanisme est le suivant :
Le nombre de répétitions sera préalablement placé dans le registre de comptage ecx.
Elle n’est valable que pour les opérations sur les chaînes de caractères.
– Lamacro-instruction rep instruction répète l’instruction présente comme opérande un certain nombre
de fois.
Exemple
rep movsb ⇔
movb %ds(%esi),%al
movb %es(%edi),%al
incl %esi
incl %edi
et ce ecx fois.

– La macro-instruction repe instruction, répète l’instruction présente comme opérande un certain nombre
de fois et ce tant que le contenu de la case mémoire pointée par (ds :esi) est égale au contenu de la
case mémoire pointée par (es :edi) et que la valeur du registre ecx 6= 0.
– La macro-instruction repne instruction, répète l’instruction présente comme opérande un certain
nombre de fois et ce tant que le contenu de la case mémoire pointée par (ds :esi) est différente
au contenu de la case mémoire pointée par (es :edi) et que la valeur du registre ecx 6= 0.
– L’instruction instruction est l’une des instructions de manipulation de chaînes de caractères vues
précédemment.
Remarque : Nous verrons lors du TP intitulé : Votre premier programme en assembleur faisant quelque
chose ?, l’utilité de toutes ces instructions.

49
Chapitre 10

Boucles et sauts

10.1 Introduction
programme n’est jamais exécuté de manière linéaire, il y a sans cesse des tests qui sont exécutés
U N
et qui engendrent des sauts vers des autres programmes ou sous programmes ou bien même des
interruptions de ce dernier.
Les instructions de branchement servent à interrompre l’exécution linéaire du programme, c’est-à-dire
que ce n’est pas l’instruction suivante qui est traitée, mais une instruction se trouvant en un autre endroit
du programme soit plus loin, soit avant.
Le problème résulte de savoir à quelle adresse mémoire on va aller pour continuer et comment va-t-on
en revenir ?
Il existe 2 types de sauts :
1. Les sauts inconditionnels
2. Les sauts conditionnels

10.2 Les sauts inconditionnels


saut inconditionnel est un saut qui ne demande aucun test, il est réalisé dés que le pointeur d’ins-
U N
truction pointe dessus. L’instruction de branchement inconditionnel du microprocesseur 8086 et aussi
des autres de la famille iAPX, est jmp, qui est l’abréviation de jump.
Exemple
.text
jmp Etiquette1
instructions suivantes dans le code source et encore
Etiquette1 :
movl $25,%eax
addl %eax,%ebx
L’instruction jmp demande au microprocesseur de charger le pointeur d’instructions eip avec la valeur de
déplacement du label Etiquette1.
L’instruction de saut inconditionnel jmp utilise un déplacement sur 32 bits, qui permet d’aller plus en
avant dans le programme ou bien de revenir en arrière. La valeur se trouvant donc après l’instruction de
saut inconditionnel est codé en complément à 21 . Avec 32 bits on peut avoir 232 combinaisons soit de −231
à +231 − 1, il est donc possible de revenir de 231−1 octets ou d’avancer de 231 − 1 octets.
Remarque : Ceci est vrai pour les sauts inconditionnels et pour les sauts conditionnels que nous allons
voir tout de suite.
1 Je rappelle que le complément à 2 est une façon de coder les nombres négatifs. Voir le chapitre intitulé le codage dans la partie

hardware de ce cours.

50
10.3 Les sauts conditionnels
sauts conditionnels sont des sauts, après une décision ou test. L’instruction de saut conditionnel est
L ES
l’équivalent de l’algorithme suivant :
Si <condition> est vrai
Alors je vais à Label
Sinon je continue
Exemple :
.text
movl $25,%eax
cmpl $25,%eax
jnb plus_grand # le saut se fera puisque le registre eax vaut 25 donc n’est pas str
instructions suivante dans le code sources
et encore .....
plus_grand : #étiquette où le programme se poursuit.

10.4 Tableau des instructions de sauts conditionnels


Nom Conditions Indicateurs
JB ou JNAE < C=1
JAE ou JNB > C=0
JBE ou JNA 6 C = 1 ou Z = 1
JA ou JNBE > C = 0 et Z = 0
JE ou JZ = Z=1
JNE ou JNZ 6= Z=0
JL ou JNGE < S6=0
JGE ou JNL > S=0
JLE ou JNG 6 Z = 1 ou S6=0
JG ou JNLE > Z = 0 ou S = 0
JP ou JPE Parité P=1
JNP ou JPO Pas de parité P=0
JS Signé S=1
JNS Non signé S=0
JC Retenue C=1
JNC Pas de retenue C=0
JO Débordement O=1
JNO Pas de débordement O=0

On rappelle la définition des différents bits du registre code condition

– O = de débordement (Overflow) – Z = de zéro (Zero)


– D = de sens (Direction) – A = de retenue auxiliaire (Auxiliary
– I = de masquage des interruptions (In- carry)
terrupt) – P = de parité (Parity)
– T = de trappe de débogage (Trap) – C = de retenue (Carry)
– S = de signe (Sign)

10.5 Boucles
existe des instructions spécialement dédiées aux boucles, ce sont les instructions
I L
loop, loope, loopne et jcxz
Les instructions de boucle sont équivalentes à l’algorithme suivant

51
Pour I = x à I < y
Alors j’exécute
les instructions y-x fois

10.5.1 Exemple de programme utilisant une instruction de saut


Affichage des 26 lettres de l’alphabet
1 # Programme affichant les 26 lettres de l’alphabet en majuscule
2 .data # zone de données
3 affiche:
4 .ascii "%c \0"
5 Alaligne:
6 .ascii "\n"
7
8 .align 4
9
10 .text
11 # on sauvegarde les registres de pile
12 # du programme appelant
13 pushl %ebp
14 movl %esp,%ebp
15
16 pusha # on sauvegarde les registres
17
18 xorl %eax,%eax
19
20 movl %ecx,$26 # 26 lettres dans l’alphabet
21 movb %al,’A’ # al recupere le code ASCII de A
22
23 Lettre_suivante:
24 pushl %eax
25 pushl $affiche
26 call puts # on affiche le caractere
27 addl $8,%esp
28
29 incb %al # al recupere le code ASCII suivant #
30 #Le registre de comptage ecx est décrémenté de 1
31 decl %ecx
32 #Le saut est fait si le registre ecx decremente est non nul.
33 jnz Lettre_suivante
34
35 pushl $Alaligne
36 call puts
37 addl $4,%esp
38
39 popa # on recupere les registres
40 # on recupere les registres de pile
41 # du programme appelant
42 leave
43 ret
Dans ce programme on a à faire à une boucle qui doit être exécuté 26 fois, donc autant utiliser une des
instructions de boucle du microprocesseur, plutôt que de réaliser un test.
On peut donc remplacer les lignes 30 et 32 à savoir

52
decl %ecx
jnz lettre_suivante
par l’instruction suivante
loop Lettre_suivante

10.5.2 Définition de ces instructions destinées aux boucles.


– L’instruction loop décrémente automatiquement le registre ecx et permet de boucler jusqu’à ce que
ce registre ecx soit nul.

– Les instructions loope ou loopz sont identiques à loop sauf que loope et loopz sortent de la boucle
également lorsque le flag zéro est positionné à 1 (le bit Z du registre code condition). Il y a également
les instructions loopne et loopnz qui sont les instructions inverses des précédentes.

– Une dernière instruction de boucle est l’instruction jcxz qui est une instruction à placer avant la boucle
dans le cas où le registre ecx peut être égal à 0 au début de boucle afin de la shunter. Sans cette ins-
truction la boucle serait exécutée 232 fois ou 4 294 967 296 fois, ce qui peut durer un certain temps 2
et faire croire au programmeur que le système est “planté”. C’est une erreur de programmation qu’il
est difficile de détecter quand on programme en langage d’assemblage.

2 Avec un microprocesseur ayant une fréquence d’horloge de 1GHz et ayant une boucle de 10 instructions, cela peut durer plusieurs

minutes, ce qui est très très long à notre époque. . .

53
Chapitre 11

Blocs de répétitions et les Macros

11.1 Introduction
blocs de répétitions et les macros sont utilisés lorsque l’on répète des séquences d’instructions. Ce
L ES
qui a pour but de simplifier l’écriture du code pour le programmeur et de le rendre plus lisible. Pendant
la phase d’asssemblage, les macros et les blocs de répétitions sont remplacés par le code correspondant,
car le microprocesseur ne peut comprendre ce “langage".

11.2 Blocs de répétition


bloc de répétition commence par la directive d’assemblage
U N

.rept
suivie du paramètre nb_de_fois et se termine par la directive d’assemblage
.endr
Le code compris à l’intérieur est assemblé autant de fois que le paramètre suivant la directive rept le
spécifie.
.rept 3
.long 0
.endr
à l’assemblage
.long 0
.long 0
.long 0
équivalent à
.long 0,0,0

11.2.1 Combinaison de REPT et du signe =


.set valeur, 0 # valeur = 0
.rept 5
.long valeur
valeur=valeur+$1
.endr
à l’assemblage

54
.long 0
.long 1
.long 2
.long 3
.long 4
Il est possible d’imbriquer les blocs de répétition.

11.3 Les Blocs de répétition et les paramètres variables


Les directives irp et irpc permettent de distribuer les éléments d’une liste de paramètres dans un bloc
de répétition en attribuant une variable à chaque passe de répétition.
– irp : remplace chaque répétition d’un paramètre par un élément de la liste associée.
– irpc : puise caractère par caractère de la chaîne associée.
Elles doivent se terminer par la directive .endr. Si on désire insérer le nom du paramètre, il faut le faire
précéder du caractère de protection 1 “\”.
La syntaxe est la suivante :
.irp symbole,valeur
.irpc symbole,valeur
Exemple
.irp param,1,2,3
.long param
.endr
à l’assemblage on obtient :
.long 0
.long 1
.long 2
Exemple :
.irpc param,123
movb $toto\param,%ah
.endr
à l’assemblage on obtient :
movb %ah, $toto1
movb %ah, $toto2
movb %ah, $toto3

11.4 Les Macros


macro n’occupe pas de place en mémoire, elle sert à simplifier le travail du programmeur. La
U NE
partie instructions d’une macro comporte en générale plusieurs commandes assembleurs, utilisant
éventuellement une <liste de paramètres>. Le fait que l’on puisse transmettre des paramètres à une macro
élargit leur champ d’application. Il est également possible de redéfinir une macro.
Les macros commencent par la directive macro et doivent se terminer par la directive .endm

11.4.1 Principe
On affecte un nom à un bloc de texte qui est le corps de la macro. Lors de l’assemblage, l’assembleur
remplacera toutes les occurrences du nom de la macro par le bloc de texte compris dans la macro.
Ressemble à la directive .INCLUDE mais plus souple d’emploi car elles peuvent recevoir des para-
mètres et contenir des labels locaux.
1 Ce caractère de protection \ est aussi utilisé dans les commandes du shell sous linux.

55
11.4.2 Exemple
la macro suivante génère une suite de nombres qui auront une zone mémoire de type long réservée.
.macro sum from=0, to=5
.long \from
.if \to-\from
sum "(\from+1)",\to
.endif
.endm
à l’assemblage on obtient :
.long 0
.long 1
.long 2
.long 3
.long 4
.long 5
autre exemple :
.macro fin
movl %ebp,%esp
popl %ebp
ret
.endm
Permettrait de ne plus avoir à écrire cette partie à la fin d’un sous programme et de rendre ainsi le code plus
court pour le programmeur.
Il est possible d’utiliser un sous-programme plutôt qu’une macro. Le code sera plus compact avec un
sous-programme car celui-ci n’est assemblé qu’une seule fois. Par contre le code sera plus rapide avec
des macros, car elles n’ont pas besoin des mécanismes d’appel et de retour de fonctions (call et ret).
De plus, elles peuvent être créées pour générer des codes variables suivant certains détails alors qu’un
sous-programme est figé.

11.4.3 Définition des labels dans les macros


Si un label existe dans une macro lors de l’assemblage, dés le deuxième appel de la macro, ce label
sera redéfini, ce qui provoquera une erreur. Il existe alors la directive local qui limite la portée du label à
l’intérieur de la macro. Cette directive doit être utilisée juste après la directive macro.

11.5 Conclusion
est possible de réécrire un langage complet en utilisant se principe de macros et de blocs de répétitions.
I L
Mais ce n’est pas le but de ce cours. . .

56
Chapitre 12

L’unité de virgule flottante : FPU

12.1 Introduction
avons vu dans le cours sur les nombres flottants que ces derniers avaient un codage particulier.
N OUS
Au début des microprocesseurs, ces derniers ne savaient pas faire de calculs en virgule flottante. Si on
voulait en faire, il fallait ajouter une bibliothèque mathématique, donc du logiciel, et les temps de calculs
étaient très long. La technologie évoluant, on a su enfin fabriquer des puces qui permettaient de faire ses
fameux calculs.
Au début, ces puces n’étaient pas intégrées dans le microprocesseur (au sens physique du terme), mais
étaient placées à côté sur la carte mère, voilà pourquoi on les appelait les coprocesseurs mathématique. Ils
étaient constitués d’un nombre de transistors bien supérieur et coûtaient bien plus chère que le micropro-
cesseur lui même. Ils avaient donc leur propre jeu d’instructions, leurs registres et étaient (et sont toujours)
capables de travailler de manière presque indépendante. Quand le microprocesseur recevait une instruction
sur des nombres flottants, il l’envoyait au coprocesseur mathématique qui s’occupait de l’exécuter et lui
renvoyait le résultat par l’intermédiaire de l’interruption hardware N˚131 .
A l’heure actuelle, et ce depuis le 486, le coprocesseur fait parti intégrante de la puce physique, mais le
principe reste toujours le même.

12.2 L’unité de virgule flottante : FPU


instructions flottantes sont au nombre de 50 et manipulent les composants d’un paquet de 80 bits
L ES
simultanément. Ces 80 bits représentent le codage d’un nombre flottant de la norme IEEE7542. Le
sigle FPU veut dire : Floating Point Unit

12.3 Les registres de la FPU


E coprocesseur mathématique possède
L – 8 registres généraux de 80 bits. Ces registres sont nommés st0 à st7 et sont utilisables comme des
registres d’usage général. Ces registres sont divisés en trois champs de format réel temporaire. On
les nomme aussi registres de pile. On les manipule comme une pile LIFO (Last In First Out), et on
peut les charger (empiler) ou stocker (dépiler). st0 étant bien sur le registre de sommet de la pile.
Voir le tableau ci-dessous.
1 Voir le chapitre intitulé : les interruptions, un peu plus loin dans ce cours.
2 Voir le cours sur le codage des nombres flottants dans la partie Hardware

57
Nom et numéro des bits
Signe Exposant Mantisse
Noms registres N˚ 79 N˚ 78 à 64 N˚ 63 à 0
st(0) ou st
st(1)
st(2)
st(3)
st(4)
st(5)
st(6)
st(7)

– Un registre d’état sur 16 bits, qui reflète l’état de la FPU et il peut être lu en le stockant dans une
variable mémoire.

– Un registre de contrôle de 16 bits, qui est utilisé pour contrôler les opérations de la FPU, notamment
la précision, donc la taille de la mantisse.

– Des registres pointeurs d’instructions et de données sur 48 bits, ils sont utilisés pour supporter la
manipulation des exceptions. Si la FPU exécute une instruction accédant à une donnée et que cette
instruction cause une exception, alors le code opératoire de cette instruction, son adresse et l’adresse
de la donnée sont stockés dans ces registres.

12.4 Définition de variables


FPU peut travailler avec trois types de variables
L A

1. Les nombres réels sur 32 (simple précision), 64 (double précision), et 80 bits (précision étendue)
2. Les entiers binaires sur 16 (Entier word), 32 (Entier court) et 64 bits (Entier long)
3. Les nombres BCD (Binary Coded Decimal : Nombres décimaux codés en binaire) 4 bits par chiffre
de base 10.
Le tableau ci-dessous résume les types de données

Type de données Nb de Bits Nb de Digits Les limites


Entier word 16 4 -32768 à 32767
Entier court 32 9 −2 ∗ 109 à 2 ∗ 109
Entier long 64 18 −9 ∗ 1018 à 9 ∗ 1018
Réel court 32 6à7 −8, 43 ∗ 10−37 à 3, 37 ∗ 1038
Réel long 64 15 à 16 −4, 19 ∗ 10−307 à 1, 67 ∗ 10308
Réel temporaire 80 19 −3, 4 ∗ 10−4932 à 1, 2 ∗ 104932
Décimal paquet 80 18 -999 999 999 999 999 999 à
+999 999 999 999 999 999

Remarque : L’unité de virgule flottante sauvegarde toutes les données en interne, en une représentation
(donc un code) réelle temporaire, cela permet d’avoir une plus grande précision lors des calculs internes à
la FPU.
Le nombre infini est représenté par
– l’exposant ne contient que des 1
– la mantisse commence par 1 et est suivi de 0.
Lorsqu’il y a une exception la représentation du nombre est représentée par :
– l’exposant ne contient que des 1
– la mantisse contient tout sauf ce que contenait la représentation du nombre infini.
Dans ce cas on récupère une information : "Pas un nombre (Not a Number NaN)

58
12.5 Les instructions FPU
permettent de faire toutes sortes d’opérations telles les opérations arithmétiques, trigonomé-
E LLES
triques, logiques, des comparaisons, des conversions, des décalages et le chargement des registres
FPU etc. . .
Elles sont au nombre de 49, et voici la définition de quelques unes d’entre elles.
Remarque : les suffixes s, l et t indiquent respectivement des données de types short (32 bits), long (64
bits) ou temporaire (80 bits).

12.5.1 Le transfert de données


Elles déplacent des données de ou vers le registre sommet st.
– Chargement : fld, fild et fbld (s, l ou t), charge dans le registre st un nombre réel, entier ou BCD.
Exemple
flds a ⇐⇒ st = a sur 32 bits
– stockage : fst ou fist (s, l ou t), stocke du registre st un nombre réel ou entier dans une case mémoire.
Exemple
fsts a ⇐⇒ mem a = st sur 32 bits
– stockage et dépilation : fstp, fIstp et fbstp (s, l ou t), stocke du registre st un nombre réel, entier ou
BCD dans une case mémoire et dépile la pile donc le registre st0 récupère la valeur du registre st et
le registre st1 celle du registre st2 etc. . .
Exemple
fstpl a ⇐⇒ mem a = st sur 64 bits
– Échange : fxch reg, elle commute les contenus du registre st avec un autre registre de la pile. Si
aucune opérande n’est donnée, l’échange se fait entre les registres st et st1.

12.5.2 Les instructions arithmétiques


Elles sont au nombre de 6.
1. fadd : C’est l’opération d’addition,
2. fsub : C’est l’opération de soustraction,
3. fmul : C’est l’opération de multiplication,
4. fdiv : C’est l’opération de division,
5. fsubr : C’est l’opération de soustraction inversée,
6. fdivr : C’est l’opération de division inversée.
Remarque : la difficulté de la programmation de la FPU vient du fait qu’il y a énormément de formes
possibles pour ces instructions arithmétiques.
– Forme registre st : st est la source et st1 est la destination
fadd, fsub, fmul et fdiv⇐⇒ st1 = st1 + - * / st
fsubr et fdivr⇐⇒ st1 = st - / st
– Forme registre pile : st est la source ou la destination et l’autre registre est l’inverse.
Exemple
fadd %st2,%st⇐⇒ st(2) = st2 + st
– Forme registre pile avec dépilation : la destination est un registre de la pile sauf pour le registre st
puisqu’il y a dépilation ! ! !
Exemple
fsubp %st,%st(2)⇐⇒ st2 =st2-st et st = st1, st1 = st2 etc...

59
– Forme mémoire : la mémoire (réel ou entier) est la source et le registre st est la destination.
Remarque :
Pour Fopcode source, l’opérande source est une variable mémoire réelle 32 ou 64 bits
Pour FIopcode source, l’opérande source est une variable mémoire entière 16, 32 ou 64 bits.
Exemple
fdivs mem1⇐⇒ st = st / mem1 (réel sur 32 bits).
fidivl mem2⇐⇒ st = st / mem2 (entier sur 64 bits).

12.5.3 Les instructions spécialisées


Elles agissent seulement sur le registre st (source et destination)
– fsqrt : réalise la racine carrée du registre st
– fxtract : décompose le registre st en son exposant et sa mantisse et les stocke dans st et st(1).
– fabs : réalise la valeur absolue du registre st
– fchs : change le signe de st

12.5.4 Les instructions trigonométriques


Elles agissent seulement sur le registre st (source et destination)
– fsin, fcos réalisent respectivement les opérations trigonométriques sinus et cosinus.
– fyl X là c’est déjà moins évident : elle réalise Z = Y ∗logX
log2 avant st = X, st1 = Y et après st = Z.

12.5.5 Les instructions de constantes


Elles sauvent un nombre utilisé sur le registre st.
Ces constantes sont au format réel temporaire et ont une précision de 19 digits.
fldy : st = 0.0
fld1 : st = 1.0
fldpi : st = 3.141592
etc...
fldy : st=log 10 / log 2
etc ....
Il existe d’autres instructions, comme les instructions de pré saut, de tests, de contrôle etc... Mais elles
dépassent largement le cadre de cette introduction.

12.6 Exemple de programme


programme écrit en langage C réalise la multiplication de 2 nombres entiers et de 2 nombres flottants.
C E

#include <math.h>
main() {
int a = 2, b ;
double c = 8.0, d, e ;
b = a*a ;
printf ("le carré de %d est : %d",a,b) ;
d = c*c ;
printf ("le carré de %f est : %f",c,d) ;
}
Si on traduit ce programme du langage C en langage d’assemblage, on obtient le code suivant, où l’on peut
constater la présence d’instructions appartenant au jeu d’instructions de l’unité de virgule flottante (voir les
lignes 31 à 33 du code).

60
1 .file "copro.c"
2 .version "01.01"
3 gcc2_compiled.:
4 .section .rodata
5 .LC0:
6 .string "le carre de %d est : %d"
7 .LC1:
8 .string "le carre de %f est : %f"
9 .text
10 .align 4
11 .globl main
12 .type main,@function
13 main:
14 pushl %ebp
15 movl %esp,%ebp
16 subl $32,%esp
17 movl $2,-4(%ebp)
18 movl $0,-16(%ebp)
19 movl $1075838976,-12(%ebp)
20 movl -4(%ebp),%edx
21 imull -4(%ebp),%edx
22 movl %edx,-8(%ebp)
23 movl -8(%ebp),%eax
24 pushl %eax
25 movl -4(%ebp),%eax
26 pushl %eax
27 pushl $.LC0
28 call printf
29 addl $12,%esp
30 #Les instructions du coprocesseur mathematique
31 fldl -16(%ebp)
32 fmull -16(%ebp)
33 fstpl -24(%ebp)
34
35 pushl -20(%ebp)
36 pushl -24(%ebp)
37 pushl -12(%ebp)
38 pushl -16(%ebp)
39 pushl $.LC1
40 call printf
41 addl $20,%esp
42 .L1:
43 leave
44 ret
45 .Lfe1:
46 .size main,.Lfe1-main
47 .ident "GCC: (GNU) [Link]"

12.7 Conclusion
’ UNITÉ de virgule flottante permet d’améliorer considérablement la vitesse d’exécution des programmes.
L Surtout les programmes tels les tableurs, les simulateurs etc ...

61
Nous aurons l’occasion de nous occuper de la programmation du coprocesseur mathématique, lors du
projet intitulé : équation du second degré.
Il existe une autre amélioration des microprocesseurs qui permet d’accroitre considérablement leurs
performances au niveau du graphisme, ce sont les instructions de type SIMD, que nous verrons dans un
prochain chapitre.

62
Chapitre 13

SIMD_MMX_SSE

13.1 Introduction
applications multimédias et de communication devenant de plus en plus gourmandes en calcul, les
L ES
fondeurs de microprocesseurs ont été obligés de penser à une nouvelle façon d’utiliser les données. En
1996, le fondeur Intel a ainsi développé la technologie MMX, il a été suivi par un autre fondeur AMD qui à
développer les instructions 3Dnow. L’analyse des algorithmes des applications de type multimédia, montre
qu’elles effectuent surtout des boucles répétitives sur des données comprises en 8 et 32 bits. Comme nous
l’avons vu au chapitre intitulé "Les ordinateurs multiprocesseurs" dans la partie “Hardware”, il existe une
façon de faire des calculs qui est de type SIMD (Single Instruction Multiple Data).
C’est ce principe qui va être utilisé avec les instructions de type MMX. On peut citer en exemple, une
image 1024x768 pixels en 65 536 couleurs : Chaque pixel occupe donc 16 bits, si on veut modifier cette
image (changer les couleurs), il faut demander au processeur d’exécuter 1024*768 fois la même instruction.

13.2 MMX
instructions MMX (MultiMédia eXtended) sont de type SIMD. Elles manipulent les composants
L ES
d’un paquet de 64 bits simultanément. Elles peuvent agir ainsi sur 8 octets, ou 4 mots, ou 2 double-
mots ou 1 quadruple-mot, il a fallu pour cela ajouter la notion de quadruple mot, sur 64 bits.
Le tableau ci-dessous montre ce découpage.

64 56 48 40 32 24 16 08 00
8 bits 8 bits 8 bits 8 bits 8 bits 8 bits 8 bits 8 bits Packed byte : 8 fois 8 bits
16 bits 16 bits 16 bits 16 bits Packed word : 4 fois 16 bits
32 bits 32 bits Packed double word : 2 fois 32 bits
64 bits Quadruple word : 1 fois 64 bits
Découpage d’un mot de 64 bits en mots de 32, 16 ou 8 bits

13.3 Les registres MMX


processeurs MMX possèdent huit registres supplémentaires de 64 bits. Ces registres sont nommés
L ES
MMX0 à MMX7 et sont utilisables comme des registres d’usage général, mais ne peuvent pas être
utilisés pour effectuer de l’adressage indexé. Afin de gagner de la place sur la puce de silicium, Intel à dé-
cider d’utiliser 8 registres MMX de 64 bits qui correspondent aux 8 registres de l’unité de virgule flottante
comme le montre le tableau ci-dessous.

63
Registre FPU de 80 bits
Registre MMX de 64 bits
st0 ou mm0 79 64 63 MMX 00
st1 ou mm1 79 64 63 MMX 00
st2 ou mm2 79 64 63 MMX 00
st3 ou mm3 79 64 63 MMX 00
st4 ou mm4 79 64 63 MMX 00
st5 ou mm5 79 64 63 MMX 00
st6 ou mm6 79 64 63 MMX 00
st7 ou mm7 79 64 63 MMX 00

13.4 Les instructions MMX


LLES sont au nombre de 57 et permettent de faire toutes sortes d’opérations telles :
E – Arithmétiques,
– Logiques,
– Des comparaisons,
– Des conversions,
– Des décalages,
– Le chargement des registres MMX.
Pour les opérations arithmétiques, il y a une nouveauté que l’on nomme saturation. Normalement, lorsqu’un
résultat dépasse les capacités des registres, on obtient une retenue qui va positionner le bit de retenue ou de
report (drapeau) dans le registre code condition. Les instructions MMX n’indiquent pas de dépassement de
capacité des registres en générant une exception ou en positionnant un drapeau.
Exemple
– Max + 1 donne Min et il n’y a pas de retenue,
– Min - 1 donne Max et il n’y a pas de retenue
– Min valant tous les bits du registre à 0
– Max valant tous les bits du registre à 1 donc
- 255,
- 65 535,
- 4 294 967 295,
- 18 446 744 073 709 551 615.
La saturation revient à ignorer la retenue et à laisser la valeur du registre à sa valeur maximale ou sa
valeur minimale.
Exemple
– Max + 1 donne Max et je retiens rien. (Max valant tous les bits du registre à 1) ou
– Min - 1 donne Min et je retiens rien. (Min valant tous les bits du registre à 0 donc 0).
Cette dernière possibilité permet une meilleure gestion de couleurs. Cela évite de vérifier si on a atteint la
couleur Max ou la couleur Min, donc de faire un test pour chaque pixel ou chaque groupe de pixels et ainsi
on gagne beaucoup de temps de traitement.

13.5 Exemple
programme réalise l’addition de 8 nombres de 8 bits en une seule instruction : voir la ligne N˚ 13 du
C E
listing ci-dessous.
1 .data
2 .align 8
3 Nombre1: .octa 0x1122334455667788
4 Nombre2: .octa 0x01020304b5069788
5 Nombre3: .octa 0x0
6 .text
7 .global main

64
8 main:
9 pushl %ebp
10 movl %esp,%ebp
11 movq Nombre1,%mm0 # charge Nombre1 dans MM0
12 movq Nombre2,%mm1 # charge Nombre2 dans MM1
13 paddb %mm0,%mm1 # additionne MM0 et MM1, octet par octet
14 movq %mm1,Nombre3 # stocke MM1 dans Nombre3
15 movl %ebp,%esp
16 popl %ebp
17 ret
Remarque : Les instructions movq et padds, paddw, paddd sont des instructions MMX. Si on revient
à l’exemple donné en introduction, on constate que le temps de modification de l’image va être divisé par
4, ce qui est loin d’être négligeable.

13.6 Le SSE
applications multimédia travaillent beaucoup sur des valeurs fractionnaires. Un moyen de supporter
L ES
ce genre de calculs consiste à fournir des opérations SIMD pour des opérandes à virgule flottante. Le
problème est que les calculs en virgule flottante sont trés coûteux en temps processeur. De plus, la plupart de
ces applications utilisent une précision de 10 à 12 bits et un écart dynamique de 4 à 6 bits est suffisant, alors
que les standards sur la virgule flottante imposent un minimum de 23 bits de précision1 . Pour la plupart
des applications, qui peuvent nécessiter la précision et l’écart dynamique de la virgule flottante standard,
les considérations en termes de performances et de simplicité d’implantation conduisent naturellement à
un compromis avec l’arithmétique en virgule fixe.
Dans ce mode de calcul, du point de vue de l’architecture du processeur, les calculs sont faits à partir
d’entiers, mais les programmeurs et leurs logiciels les interprètent comme des valeurs fractionnaires. Un
certain nombre de bits, déterminés par l’application, est interprété comme un entier, et les bits restants le
sont comme une fraction. C’est la responsabilité de l’application que de réaliser les décalages nécessaires
afin de modifier la taille du nombre.
On peut noter que ces limitations sont surmontées par les Streaming SIMD Extensions, qui fournissent
un support SIMD pour quatre flottants simple précision (4 x 32 bits = 128 bits).

13.7 Conclusion
technologies MMX et SSE ont permises d’accélérer le traitement des images en 2D et en 3D, mais
L ES
les choses évoluant très vite2 , il a fallu encore implémenter de nouvelles instructions au cœur des
microprocesseurs et est alors apparu les instructions SSE2.
La solution n’est plus d’augmenter le nombre d’instructions mais d’augmenter le nombre d’unités
capables de réaliser des calculs sur les données donc de passer d’une architecture
– SISD (Single Instruction, Single Datum) pour les microprocesseurs allant jusqu’au Pentium
– à SIMD (Single Instruction, Multiple Data) pour les microprocesseurs allant jusqu’au P4
– puis MIMD (Multiple Instructions, Multiple Data) pour les microprocesseurs à partir du P4 Hyper
Threading ou des processeursà double-coeur 3.
Techniquement, le concept SIMD met donc en jeu :
– De nouveaux types de données : des paquets dont les constituants sont de tailles adaptées aux appli-
cations,
– De nouveaux registres : dont la taille permet de manipuler ces paquets,
– De nouvelles instructions : basées sur l’étude par les ingénieurs d’Intel des opérations les plus cou-
rantes dans la manipulation de données multimédias.
1 Voirle chapitre intitulé l’Unité de virgule Flottante
2 Lesjeux aussi :)
3 Mais cela est un autre cours...

65
Chapitre 14

Les Interruptions

14.1 Introduction
NE interruption est une indication qui requiert l’attention du microprocesseur.
U Quand une interruption survient, le microprocesseur
– interrompt son traitement en cours,
– sauvegarde son contexte de travail
– exécute un “sous-programme” résident en mémoire dénommé routine d’interruption (ou handler
d’interruption).
Après qu’une routine d’interruption ait accompli sa tâche, le microprocesseur reprend son traitement au
point où est survenue l’interruption. Une interruption peut survenir à n’importe quel moment de l’exé-
cution d’un programme. Par définition, les interruptions sont asynchrones par rapport aux opérations du
microprocesseur : il ne suffit pas de reproduire l’état du processeur lors de l’interruption pour la reproduire.
Une interruption peut être provoquée par :
– Un des composants électroniques de l’unité centrale (interruption matérielle),
– Le programme qu’exécute le microprocesseur (interruption logicielle),
– Une erreur dans le programme (exception).
La figure ci dessous montre les différents types d’interruptions

F IG . 14.1 – Les différents types interruptions

Ces deux dernières sont synchronisées avec les opérations du microprocesseur.

14.2 Les interruptions matérielles


interruption matérielle est un arrêt de l’exécution séquentielle des instructions d’un programme
U NE
demandée par un des composants de l’unité centrale suite à un événement matériel particulier.

66
Exemples
– L’appui sur une touche du clavier,
– Le déplacement de la souris,
– Un manque de papier dans l’imprimante
– Etc...
Cette interruption provoque l’exécution d’une routine d’interruption, c’est-à-dire d’un programme de trai-
tement de l’événement survenu et propre à cet événement.
Les signaux d’interruption permettent aux différents composants du système, d’attirer l’attention du
microprocesseur afin de déclencher une opération déterminée. Comme plusieurs demandes d’interruption
peuvent survenir simultanément, elles sont tout d’abord envoyées à une entité que l’on nomme Contrôleur
d’Interruption (PIC : Programmable Interrupt Controler) qui les retransmet ensuite au microprocesseur.

14.2.1 Le PIC 8259


Le PIC attribue pour ce faire un rang de priorité déterminé à chaque demande d’interruption (IRQ :
Interrupt Request) en fonction de son origine et retransmet en premier lieu la demande d’interruption dont
le rang est le plus élevé. Le PIC délivre sur le bus de données le numéro de la routine d’interruption à
exécuter, à l’intention du microprocesseur.
Le contrôleur d’interruptions (INTEL R 8259) du PC XT peut traiter jusqu’à 8 demandes d’interruption
simultanées (8 entrées IRQ(0) à IRQ(7)).
La figure ci-dessous illustre cet organisation logique.

F IG . 14.2 – Le contrôleur d’interruption 8259

14.2.2 Les 2 PIC 8259 en cascade


Comme ce serait insuffisant pour l’exploitation du PC AT, deux contrôleurs d’interruption ont été mis
en cascade pour que puissent être traitées simultanément jusqu’à 15 demandes d’interruption.
Comme le montre la figure ci-dessous.

F IG . 14.3 – Les contrôleurs d’interruption 8259 en cascade

14.2.3 L’IO_APIC
Les micro-ordinateurs devenant multiprocesseurs les concepteurs de ces dernières ont défini une nou-
velle architecture permettant de gérer plus d’interruption

67
F IG . 14.4 – L’IO APIC

A l’heure actuelle, ce n’est pas 15 interruptions différentes dont on dispose mais de 24. C’est ce que l’on
nomme l’APIC. Si vous jetez un œil sur le fichier /usr/src/linux/include/asm/irq.h qui se trouve ci-dessous,
vous pouvez lire à la ligne 27
Define NR_IRQS 24
Ce qui donne le nombre d’interruptions possibles.

1 #ifndef _ASM_IRQ_H
2 #define _ASM_IRQ_H
3
4 /*
5 * linux/include/asm/irq.h
6 *
7 * (C) 1992, 1993 Linus Torvalds, (C) 1997 Ingo Molnar
8 *
9 * IRQ/IPI changes taken from work by Thomas Radke
10 * <tomsoft@[Link]>
11 */
12
13 #include <linux/config.h>
14

68
15 #define TIMER_IRQ 0
16
17 /*
18 * 16 8259A IRQ’s, 208 potential APIC interrupt sources.
19 * Right now the APIC is mostly only used for SMP.
20 * 256 vectors is an architectural limit. (we can have
21 * more than 256 devices theoretically, but they will
22 * have to use shared interrupts)
23 * Since vectors 0x00-0x1f are used/reserved for the CPU,
24 * the usable vector space is 0x20-0xff (224 vectors)
25 */
26 #ifdef CONFIG_X86_IO_APIC
27 #define NR_IRQS 224
28 #else
29 #define NR_IRQS 16
30 #endif
31
32 static __inline__ int irq_cannonicalize(int irq)
33 {
34 return ((irq == 2) ? 9 : irq);
35 }
36
37 extern void disable_irq(unsigned int);
38 extern void disable_irq_nosync(unsigned int);
39 extern void enable_irq(unsigned int);
40 extern void release_x86_irqs(struct task_struct *);
41
42 #ifdef CONFIG_X86_LOCAL_APIC
43 #define ARCH_HAS_NMI_WATCHDOG /* See include/linux/nmi.h */
44 #endif
45
46 #endif /* _ASM_IRQ_H */

Sous Linux si vous lancez la commande


cat /proc/interrupts
vous obtenez quelque chose comme :

47 CPU0
48 0: 107244 XT-PIC timer
49 1: 1770 XT-PIC keyboard
50 2: 0 XT-PIC cascade
51 4: 0 XT-PIC usb-uhci
52 5: 22362 XT-PIC usb-uhci
53 8: 1 XT-PIC rtc
54 10: 0 XT-PIC ehci_hcd, Intel ICH4
55 11: 0 XT-PIC usb-uhci
56 14: 17225 XT-PIC ide0
57 15: 1971 XT-PIC ide1
58 NMI: 0
59 ERR: 0

– La première colonne donne le N˚ de l’interruption matérielle.

69
– La seconde donne le nombre de fois que l’interruption matérielle à été utilisée depuis que vous avez
allumé votre micro-ordinateur 1.
– La troisième est sans importance.
– La quatrième donne le nom du périphérique attaché à ce N˚ de l’interruption matérielle.
On peut comparer ce résultat avec le tableau du chapitre : La table des vecteurs d’interruption se trouvant
un peu plus loin.

14.3 Les interruptions logicielles


interruption logicielle est un arrêt de l’exécution séquentielle des instructions d’un programme
U NE
"A" pour exécuter les instructions d’une routine d’interruption. Ces routines font partie du
– BIOS (Basic Input Output System)
– Du système d’exploitation (DOS, Linux...).
Ce type d’interruption est provoquée par une instruction du langage d’assemblage du microprocesseur int
n˚ dans le programme "A". Le programme d’interruption qui est alors exécuté est celui dont le numéro suit
l’instruction int.

14.3.1 Celles du DOS


La principale est la numéro 21h, nous verrons quelle contient énormément de services, lors d’un tp
spécifique au DOS et au matériel.

14.3.2 Celles du BIOS


Elle permettent d’initialiser la machine au démarage, et ne sont plus utilisées par la suite sous Linux.
Elles le sont sous DOS mais plus sous NT. Nous verrons leur utilisation lors d’un tp spécifique au matériel.

14.3.3 Celles de Linux


On ne les nomme pas des interruptions mais des appels systèmes. Dans le noyau 2.4 elles sont au
nombre de 270, et dans le noyau 2.6 il y en a 4 de plus. Vous pouvez trouver leur définition dans le fichier
/usr/src/linux/include/asm/unistd.h.
Voici à quoi cette liste ressemble.

60 /*
61 * This file contains the system call numbers.
62 */
63
64 #define __NR_exit 1
65 #define __NR_fork 2
66 #define __NR_read 3
67 #define __NR_write 4
68 #define __NR_open 5
69 #define __NR_close 6
70 #define __NR_waitpid 7
71 #define __NR_creat 8
72 #define __NR_link 9
73 #define __NR_unlink 10
74 #define __NR_execve 11
75 #define __NR_chdir 12
76 #define __NR_time 13
1 Faites plusieurs cat /proc/interrupts et vous verrez que la première ligne qui concerne l’interruption N˚ 0, donc le timer change

souvent et aussi la seconde qui vous donne le nombre de fois que vos petits doigts ont frolés le clavier... On sait tout sur vous :)

70
14.4 Les exceptions
exception est la réponse normale, documentée et prévisible du microprocesseur à une situation
U NE
détectée lors de l’exécution d’une instruction et qui nécessite une gestion spéciale. Les exceptions
peuvent être reproduites en exécutant la même série d’instructions que celle qui a généré la première
exception. Elles sont similaires aux interruptions car elles forcent un transfert de contrôle. Toutefois, elles
sont internes au microprocesseur et ne peuvent pas être masquées. Les exceptions ont toujours une priorité
plus grande que les signaux des lignes INTR ou NMI. La catégorie des exceptions du microprocesseur est
subdivisée en trois classes d’exceptions :
1. Les fautes,
2. Les trappes,
3. Les arrêts.
La classification d’une exception dépend du moment où elle est détectée et de la possibilité de réexécuter
l’instruction qui l’a générée.

14.4.1 Les fautes


Une faute est une exception rapportée avant l’exécution de l’instruction. La faute est détectée avant
l’exécution, ou bien le microprocesseur se replace dans l’état d’avant l’exécution. Dans les deux cas, si la
cause de la faute est supprimée, l’instruction peut être tentée à nouveau. Les registres cs et ip sauvés en pile
pointent sur l’instruction fautive.

14.4.2 Les trappes


Une trappe est une exception détectée lors de l’exécution d’une instruction et elle est reportée au dé-
but de l’instruction suivante. L’instruction qui a causé l’exception peut toujours être en cours d’exécution
lorsque l’exception est détectée et générée. si une trappe est détectée lors d’un transfert de contrôle, les
valeurs de cs et ip placés en pile pointent sur l’instruction vers laquelle le contrôle aura été transféré.

14.4.3 Les arrêts


Un arrêt est une exception provoqué par le microprocesseur lorsqu’il se trouve face à une erreur grave.
Un arrêt peut provenir d’une panne matérielle, ou de valeurs incohérentes dans les tables du système. En
raison de la nature de ces erreurs, l’opération qui a causé l’erreur ne peut pas être identifié et le programme
ne peut pas être relancé.
Exemple
Si au cours d’un traitement normal la table des descripteurs globaux s’avère invalide, il est impossible
de remonter dans l’exécution pour savoir comment cela est arrivé.

14.5 La table des vecteurs d’interruption


microprocesseur 8086 supporte 256 interruptions différentes, chacune étant identifiée par un numéro
L E
compris entre 0 et f f16 (255 en décimal). L’adresse de début d’une routine d’interruption est appelée
Vecteur d’interruption. Toutes les adresses (logique cs :ip) de début de ces vecteurs sont rangées dans une
table et constituent donc la Table des Vecteurs d’Interruption. Cette table se charge en RAM à partir de
l’adresse la plus basse 0000 : 000016 .
Chaque vecteur d’interruption est stocké sur 4 octets, 2 pour le registre cs et 2 pour le registre ip.
Le tableau ci-desous montre cette table.
En caractères gras on peut voir celles qui sont utilisés par le système d’exploitation Linux du
cat /proc/interrupts
précédent.

71
N˚ @ F ONCTION RÉALISÉE N˚ @ F ONCTION RÉALISÉE

00 000-003 CPU : D IVISION PAR ZÉRO 1E 078-07B @ DE LA TABLE DES PARAM . DISQUETTE

01 004-007 CPU : PAS À PAS 1F 07C-07F @ DES MODÈLES BITS DE CARACTÈRE

02 008-00B CPU :NMI( DÉFAUT CIRCUIT RAM) 20 080-083 DOS : F IN DU PROGRAMME .

03 00C-00F CPU : B REAK POINT ATTEINT 21 084-087 DOS : A PPELER FONCTIONS DOS

04 010-013 CPU : D ÉBORDEMENT NUMÉRIQUE 22 088-08B @ ROUTINE DOS FIN PROGRAMME

05 014-017 C OPIE D ’ ÉCRAN 23 08C-08F @ ROUTINE CTRL BREAK

06 018-01B I NSTRUCTION INCONNUE ( QUE 286) 24 090-093 @ ROUTINE ERREUR DOS

07 01C-01F R ÉSERVÉ 25 094-097 DOS : L IRE DISQUETTE / DISQUE DUR

08 020-023 IRQ0 : T IMER 26 098-09B DOS : E CRIRE DISQUETTE / DISQUE DUR

09 024-027 IRQ1 : C LAVIER 27 09C-09F DOS : F IN PRG . L AISSER RÉSIDENT

0A 028-02B IRQ2 : 2nd 8259 (AT UNIQUEMENT ) 28-3F 0A0-0FF R ÉSERVÉ DIFFÉRENTES FONCTIONS

0B 02C-02F IRQ3 : I NTERFACE SÉRIE 2 40 100-103 BIOS : F ONCTIONS DISQUETTES

0C 030-033 IRQ4 : I NTERFACE SÉRIE 1 41 104-107 @ TABLE DISQUE DUR N˚ 1

0D 034-037 IRQ5 : D ISQUE DUR 42-45 108-117 R ÉSERVÉS

0E 038-03B IRQ6 : D ISQUETTE 46 118-11B @ TABLE DISQUE DUR N˚ 2

0F 03C-03F IRQ7 : I MPRIMANTE 47-49 11C-127 L IBRES

10 040-043 BIOS : F ONCTION VIDÉO 4A 128-12B H EURE ALARME ATTEINTE (AT)

11 044-047 BIOS : D ÉTERMINER CONFIGURATION 4B-67 12C-19F L IBRES

12 048-04B BIOS : D ÉTERMINER LA TAILLE 68-6F 1A0-1BF I NUTILISÉS

MÉMOITE D E LA RAM

13 04C-04F BIOS : DISQUETTES / DISQUE DUR 70 1C0-1C3 IRQ8 : H ORLOGE TEMPS RÉEL (AT)

14 050-053 BIOS : A CCÈS À L’ INTERFACE SÉRIE 71 1C4-1C7 IRQ9 : (AT)

15 054-057 BIOS : CASSETTES OU ÉTENDUES 72 1C8-1CB IRQ10 : (AT)

16 058-05B BIOS : T EST DU CLAVIER 73 1CC-1CF IRQ12 : (AT)

17 05C-05F BIOS : A CCÈS À L’ IMPRIMANTE // 74 1D0-1D3 IRQ13 : 80287 NMI (AT)

18 060-063 A PPEL DU BASIC EN ROM 75 1D4-1D7 IRQ14 : D ISQUE DUR (AT)

19 064-067 BIOS : CTRL ALT DEL 76 1D8-1DB IRQ15 : (AT)

1A 068-06B BIOS : L IRE DATE ET HEURE 77 1DC-1DF I NUTILISÉS

1B 06C-06F TOUCHE B REAK ACTIONNÉE 78-7F 1E0-1FF U TILISÉS PAR L’ INTERPRÉTEUR BASIC

1C 070-073 A PPELÉ APRÈS TOUT INT 08 80-F0 200-3C3 I NUTILISÉS

1D 074-077 @ DE LA TABLE DES PARAM . VIDÉO F1-FF 3C4-3CF I NUTILISÉS

14.6 Gestion des interruptions


Le microprocesseur 8086 dispose de 3 lignes d’interruption
L E

1. RESET (21) : Réinitialisation


2. NMI (17) : Interruption non masquable
3. INTR(18) : Demande d’interruption
Deux instructions int et intro permettent une interruption de type logicielle. Le retour d’un programme
est réalisé par l’instruction iret. L’interruption logicielle est la plus prioritaire puis vient le NMI et enfin
l’INTR.

14.6.1 Le RESET
La ligne RESET est une ligne d’entrée asynchrone. Pour être pris en compte le signal RESET doit
être à 1 pendant au moins quatre périodes d’horloge (une impulsion de 30µs est nécessaire à la mise sous
tension).

72
Déroulement de la réinitialisation :
Le 8086 termine toute opération dés qu’apparaît une transition de 0 à 1 sur la ligne RESET. Le mi-
croprocesseur reste alors inactif jusqu’à ce qu’une transition de 1 à 0 apparaisse. Alors il faut environ 10
périodes d’horloge pour exécuter les opérations suivantes
– Mise à zéro du registre d’état. (CCR),
– Le registre cs prend la valeur f f f f16 ,
– Les registres ds, es et ss et ip sont remis à zéro.
La première instruction rencontrée est un FAR JUMP à une routine appelée Self Test POST à l’adresse
F000 :E05B. Cette routine teste la valeur stockée dans la variable BIOS 0040 :0078. Selon cette valeur,
l’initialisation sera de type "à chaud" (égale à 1414H) ou "à froid" (différent de 1414H).
– Une Initialisation "à froid" est effectuée à chaque mise sous tension. Elle met en œuvre un test
complet des mémoires RAM et ROM, des périphériques et le chargement de la partie résidente du
DOS en mémoire vive. On dit aussi que c’est un reset matériel ou hardware
– Une initialisation "à chaud" est effectuée à chaque appui simultané sur les touches CTRL ALT
DEL. Elle est comparable à l’initialisation "à froid", à ceci prés que la mémoire n’est plus testée
(donc démarrage plus rapide) on dit aussi que c’est un reset logiciel ou software, cela correspond à
un reboot sous Linux.

14.7 Interruption logicielle


NE interruption logicielle peut survenir dans les cas suivants :
U - Une tentative de division par zéro.
- L’exécution de l’instruction int.
- L’exécution de l’instruction into si le bit O du registre code condition est positionné 1.
Déroulement d’une interruption logicielle :
– Sauvegarde du registre code condition CCR dans la pile et décrémentation du registre sp de deux.
– Mise à zéro des indicateurs I et T. Ceci interdit les autres interruptions masquables et le mode pas à
pas.
– Sauvegarde dans la pile du registre ip et décrémentation du registre sp de deux adresses.
– A partir du numéro d’interruption choisi, le microprocesseur multiplie par quatre ce numéro afin
d’obtenir la première adresse du vecteur dans la table des vecteurs d’interruptions. Le contenu de
cette case mémoire sera l’octet de poids faible du registre ip, et le contenu de l’adresse suivante est
l’octet de poids fort du registre ip.
– Sauvegarde dans la pile du registre de segment cs et décrémentation du registre sp de deux adresses.
– Le contenu de l’adresse suivante dans la table des vecteurs d’interruption sera l’octet de poids faible
du registre de segment cs, et le contenu de l’adresse suivante est l’octet de poids fort du registre cs.

14.7.1 NMI
Une interruption de type NMI est activée par un front montant sur sa broche.
Déroulement d’une interruption NMI :
– Sauvegarde du registre code condition CCR dans la pile et décrémentation du registre sp de deux
adresses.
– Mise à zéro des indicateurs I et T. Ceci interdit les autres interruptions masquables et le mode pas à
pas.
– Les registres cs et ip sont chargés comme précédemment avec les valeurs du vecteur d’interruption
numéro 2.

73
14.7.2 INTR
Une interruption INTR est activée par un niveau haut sur sa broche.
Déroulement d’une interruption INTR
– Dans ce type d’interruption c’est le dispositif créateur de l’interruption (8259) qui doit déposer sur
le bus de données un octet qui sera interprété comme une partie du vecteur d’interruption. L’unité de
Gestion de Bus (BIU) exécutera deux cycles bus d’acquittement d’interruption.
– En réponse au second cycle d’acquittement, le dispositif interrompant doit envoyer un octet de don-
nées sur les lignes du bus de données AD0-AD7. Multipliée par quatre, cette valeur donne l’adresse
du début du vecteur d’interruption.
– Sauvegarde du registre code condition CCR dans la pile et décrémentation du registre sp de deux
adresses.
– Mise à zéro des indicateurs I et T. Ceci interdit les autres interruptions masquables et le mode pas à
pas.
– Les registres cs et ip sont chargés comme précédemment. - Début de la routine d’interruption avec la
nouvelle valeur de cs :ip. La routine d’interruption doit se terminer par l’instruction iret qui restaure
les registres cs et ip.

14.8 Le mode pas à pas


microprocesseur 8086 passe dans le mode pas à pas lorsque l’indicateur T est positionné 1. Dans
L E
ce mode, le microprocesseur 8086 exécute une interruption de type logicielle après l’exécution de
chaque instruction (vecteur 1). Il n’existe pas d’instruction positionnant l’indicateur T à 1. L’indicateurT
peut être modifié en changeant une image dans la pile grâce aux instructions pushf et popf qui agissent sur
les indicateurs. L’indicateur T est mis à 1 par un OU logique avec la valeur 010016 et mis à 0 par un ET
logique avec la valeur complémentée de la précédente donc f ef f16 .

14.9 Le BIOS
les ordinateurs possèdent un BIOS (Basic Input Output System) qui leur est propre. Les PC XT,
T OUS
AT et compatibles n’échappent pas à cette règle. Le rôle principal du BIOS est de fournir un en-
semble de fonctions élémentaires destinées à gérer les communications entre l’unité centrale et les organes
périphériques (clavier, écran, lecteurs de disques, RS232, mémoire, etc).
Sur les PC XT, AT et compatibles, le BIOS est implanté en memoire ROM, au-delà de l’adresse
f 000 : c00016 . Il est accessible à travers plusieurs interruptions logicielles spécialisées. La plupart de ces
interruptions se divisent en fonctions qui sont accessibles grâce au registre ah du microprocesseur. Chaque
fonction demande un ou plusieurs paramètres en entrée. Ces paramètres sont passés à la fonction par l’inter-
médiaire des registres du microprocesseur. De même, certaines fonctions renvoient un ou plusieurs résultats
lorsqu’elles ont fini de s’exécuter. Ces résultats sont accessibles directement ou indirectement à travers les
registres du microprocesseur.
Un appel typique d’une fonction BIOS s’effectue donc selon les étapes suivantes
– Initialisation des registres du microprocesseur.
– Appel de l’interruption rattachée à la fonction
– Exploitation des registres en sortie de la fonction
Le BIOS manipule de nombreuses variables qui ne peuvent être implantées en mémoire ROM en raison de
leur nature. Elles sont implantées à partir de l’adresse 0040 :0000 jusqu’à 005f : f f f f16 juste derrière la
table des vecteurs d’interruption.

74
14.10 Des exemples sous Linux
Si vous allez jeter un coup d’œil dans les sources du système d’exploitation, vous pourrez lire le source
suivant :
1 #ifndef _ASM_IRQ_H
2 #define _ASM_IRQ_H
3
4 /*
5 * linux/include/asm/irq.h
6 *
7 * (C) 1992, 1993 Linus Torvalds, (C) 1997 Ingo Molnar
8 *
9 * IRQ/IPI changes taken from work by Thomas Radke
10 * <tomsoft@[Link]>
11 */
12
13 #include <linux/config.h>
14
15 #define TIMER_IRQ 0
16
17 /*
18 * 16 8259A IRQ’s, 208 potential APIC interrupt sources.
19 * Right now the APIC is mostly only used for SMP.
20 * 256 vectors is an architectural limit. (we can have
21 * more than 256 devices theoretically, but they will
22 * have to use shared interrupts)
23 * Since vectors 0x00-0x1f are used/reserved for the CPU,
24 * the usable vector space is 0x20-0xff (224 vectors)
25 */
26 #ifdef CONFIG_X86_IO_APIC
27 #define NR_IRQS 224
28 #else
29 #define NR_IRQS 16
30 #endif
31
32 static __inline__ int irq_cannonicalize(int irq)
33 {
34 return ((irq == 2) ? 9 : irq);
35 }
36
37 extern void disable_irq(unsigned int);
38 extern void disable_irq_nosync(unsigned int);
39 extern void enable_irq(unsigned int);
40 extern void release_x86_irqs(struct task_struct *);
41
42 #ifdef CONFIG_X86_LOCAL_APIC
43 #define ARCH_HAS_NMI_WATCHDOG /* See include/linux/nmi.h */
44 #endif
45
46 #endif /* _ASM_IRQ_H */
En lançant la commande
cat /proc/ioports

75
On peut voir les plages d’adresses d’entrée-sortie occupée par les différents périphériques de votre micro-
ordinateur.
1 Resultat de la commande
2 cat /proc/ioports
3 sur un ordinateur moderne...
4
5 0000-001f : dma1
6 0020-003f : pic1
7 0040-005f : timer
8 0060-006f : keyboard
9 0070-007f : rtc
10 0080-008f : dma page reg
11 00a0-00bf : pic2
12 00c0-00df : dma2
13 00f0-00ff : fpu
14 0170-0177 : ide1
15 01f0-01f7 : ide0
16 0376-0376 : ide1
17 0378-037a : parport0
18 037b-037f : parport0
19 03c0-03df : vga+
20 03f6-03f6 : ide0
21 0cf8-0cff : PCI conf1
22 1800-1807 : Intel Corp. 82852/855GM Integrated Graphics Device
23 1810-181f : Intel Corp. 82801DBM Ultra ATA Storage Controller
24 1810-1817 : ide0
25 1818-181f : ide1
26 1820-183f : Intel Corp. 82801DB USB (Hub #1)
27 1820-183f : usb-uhci
28 1840-185f : Intel Corp. 82801DB USB (Hub #2)
29 1840-185f : usb-uhci
30 1860-187f : Intel Corp. 82801DB USB (Hub #3)
31 1860-187f : usb-uhci
32 1880-189f : Intel Corp. 82801DB/DBM SMBus Controller
33 18c0-18ff : Intel Corp. 82801DB AC’97 Audio Controller
34 18c0-18ff : Intel ICH4
35 1c00-1cff : Intel Corp. 82801DB AC’97 Audio Controller
36 1c00-1cff : Intel ICH4
37 2000-207f : Intel Corp. 82801DB AC’97 Modem Controller
38 2400-24ff : Intel Corp. 82801DB AC’97 Modem Controller
39 3000-30ff : Realtek Semiconductor Co., Ltd. RTL-8139/8139C/8139C+
On peut faire quelques comparaisons avec le tableau du chapitre : La table des vecteurs d’interruptions
vu auparavant.

76
Chapitre 15

Le mode protégé

chapitre est surement le plus complexe, donc le plus difficile à assimiler1 . Je ne vous demande pas de
C E
tout assimiler, mais de voir les mécanismes que les concepteurs des microprocesseurs ont du mettre
en œuvre pour passer :
– D’un micro-ordinateur qui tournait sous dos en mode texte et permettait de jouer au tennis avec deux
barres blanches verticales et une balle carrée...
– A un micro-ordinateur faisant tourner X-Windows, plus la lecture du dernier dvd, tout en jouant au
dernier jeu à la mode et prévenant par mail l’étudiant qu’il est l’heure d’aller en amphi. . .
Bref : Passer du mono tâche au multi tâches...

15.1 Introduction
système d’exploitation DOS ne connaît et n’utilise que le mode Réel qui est celui du microprocesseur
L E
8086. Les autres systèmes d’exploitation tel que OS/2, Unix, Windows NT et Linux permettent le
travail en multitâche et gère une mémoire virtuelle.
La même observation s’applique au BIOS, qui est en ROM et qui a été conçu pour être exécuté en
mode Réel : en cas de déclenchement du mode protégé le premier appel au BIOS entraîne inévitablement
un “plantage” du système.
Les concepteurs de logiciels ont recherché un moyen de rendre opérationnel le mode Protégé sous
système d’exploitation DOS, et pour cela ils ont écrit des gestionnaires d’exploitation multitâche qui, à son
insu, placent système d’exploitation DOS sous le contrôle d’un autre système en mode Protégé. Il a fallu
attendre une bonne dizaine d’années, entre l’apparition des premiers microprocesseurs permettant le mode
Protégé et les premiers logiciels grand public tels Windows 32 bits et OS/2.0 pouvant le gérer.

15.2 Quelques définitions


– Tâches : ce sont les différents programmes exécutés " simultanément " par le microprocesseur, en
fait on parle d’ “Unité d’exécution” ou de processus.
– Mode multi-utilisateurs : si un même programme est " lancé " plusieurs fois par plusieurs utilisa-
teurs, le code n’est chargé qu’une fois en mémoire ! Par contre, on affecte à chaque utilisateur une
zone de données propre appelée " Zone d’adressage Local " et qui n’est accessible que par la tâche à
laquelle elle est affectée. Les programmes doivent pouvoir accéder à des données et des éléments du
système d’exploitation, cette zone est appelée " Zone d’adressage Global ".
– Mémoire virtuelle : c’est un mécanisme qui permet de mettre à la disposition des programmes plus
de mémoires que la machine n’en possède physiquement. Le système d’exploitation et le micro-
processeur assurent la gestion de cette mémoire. Le principe consiste à utiliser pour le stockage, un
1 Si il y a plus complexe, l’HyperThreading, plus tard...

77
support tel que le disque dur, et à ne charger en RAM que la partie de données et de code actuellement
utilisée par la tache en cours d’exécution. On parle de " Swapping "2 .
– Le mode protégé : protected mode en anglais, il consiste à protéger l’espace mémoire appartenant à
un processus des autres processus.

15.3 Les registres du 286 en mode protégé


mode protégé, les microprocesseurs utilisent en plus des registres habituels ax, bx, cs, ip etc. . . des
E N
registres spéciaux permettant de gérer ce mode protégé.
Les anciens

16 bits 16 bits
16 bits 8 bits 8 bits
AX AH AL Accumulateur CS Segment de code
BX BH BL Base DS Segment de données
CX CH CL Compteur ES Extra segment
DX DH DL Données SS Segment de pile

SP Pointeur de pile IP Pointeur d’instructions


BP Pointeur de base
SI Index source FLAG Registre de flag
DI index destination
Auquels on ajoute
MSW Mot d’état de machine
TR Registre de tâches
GDTR 3 Pointeurs sur
LDTR les tables des
IDTR descripteurs

Les registres TR, GDTR, LDTR et IDTR seront expliqués plus loin.

Le registre MSW

F IG . 15.1 – Le MSW

Ce registre contient 4 bits qui permettent d’indiquer au microprocesseur l’état dans lequel il est et s’il
est en mode réel ou en mode virtuel.

15.4 La Gestion de la mémoire virtuelle


mémoire virtuelle est de la mémoire dont le microprocesseur dispose, mais qui n’existe pas physi-
L A
quement dans la machine. Par analogie on peut dire que la mémoire physique correspond à la mémoire
que vous avez dans votre boîte craniène et la mémoire virtuelle à ce support papier que vous essayez en
vain de retenir et que vous ne mémorisez que le temps du contrôle... :)
2 Voir le chapitre intitulé la gestion des entrées sorties la section tampons dans la partie Hardware

78
15.4.1 Format d’une adresse virtuelle en mode protégé
Cette manière de procéder implique que le programme n’accède plus à la mémoire au travers des
adresses physiques (comme en mode Réel), mais au moyen d’adresses " virtuelles ".
L’offset est identique, mais le segment représente un pointeur sur un tableau qui décrit le segment
concerné. On ne parle plus de segment mais de sélecteur de segment. D’où la notion de " Zones d’adressage
Global ou Local ", car il existe un tableau décrivant les segments mémoire globaux, et, pour chaque tâche,
un tableau décrivant les segments mémoire locaux, leur nom est " Table de descripteur ".
Les segments ne sont plus obligés, comme en mode réel, de commencer à une adresse divisible par 16,
mais " n’importe où ", et leur taille n’est plus obligatoirement de 64 kilo-Octets mais peut varier de 1 Octet
à 64 kilo-Octets.
Format d’une adresse mémoire en mode protégé.

15 0 15 0
Offset Index TI RPL
Sélecteur de segment

Les descripteurs de segments globaux ou locaux doivent contenir 2 informations importantes :


1. L’adresse de début du segment
2. La taille du segment.

7 0 7 0
Réservé au microprocesseur 386 +8
Octet d’état Bits 16 à 23 de l’adresse de segment +4
Bits 0 à 15 de l’adresse de segment +2
Longueur du segment +0

Il occupe 8 octets de mémoire.


L’adresse de début du segment est codée sur 24 bits ce qui correspond à 24 mega-Octets soit la capacité
mémoire adressable maximale du 80286 (mémoire physique).
La famille des descripteurs de segments comprend :
– Les descripteurs de Données,
– Les descripteurs de Code,
– Les descripteurs de Système.
Ils ne diffèrent que par le sens attribué aux bits de l’octet d’état, et la structure est identique.
Exemple
– Pour le descripteur de Données, l’octet d’état permet de savoir si on est dans une zone mémoire en
lecture ou écriture, si cette zone mémoire est physique ou virtuelle etc...
Si on est en mémoire virtuelle et que le programme veut y accéder, le microprocesseur ordonne au
système d’exploitation de la charger en mémoire physique.
– Pour le descripteur de Code, il permet de savoir si on est en lecture seulement, ou s’il y a possibilité
d’exécution, et comme pour les données si le segment est en mémoire physique ou virtuelle etc...
– Pour le descripteur de Système, qui est en " Zone d’adressage Global ", les bits de l’octet d’état ne
décrivent pas des segments, mais certains objets tels que :
– Des segments de tâches
– Des tables de descripteurs locaux.

15.4.2 Les registres permettant la gestion de la mémoire virtuelle


– Le registre gdtr (Global Descriptor Table Register)
Il permet de connaître l’adresse de début de la table des descripteurs globaux. Il contient les 24 bits
de l’adresse de début + la longueur, cette longueur indique le nombre de descripteurs enregistrés, qui
sont gérés par le microprocesseur au moyen de 8 octets.

79
– Le registre ldtr (Local Descriptor Table Register)
Il contient des informations sur la table de descripteurs locaux de la tache en cours. Il s’agit du
numéro sous lequel le descripteur correspondant est enregistré, son adresse et sa longueur.
Il n’existe qu’une seule table de descripteurs globaux pour toutes les tâches et gdtr n’est pas modifié
par un changement de tâche, le registre ldtr décrit après chaque changement de tâche la nouvelle
table de descripteurs locaux.

15.4.3 Taille de la mémoire virtuelle adressable par le 80286


Chaque table des descripteurs locaux peut atteindre 64kOctets, de même pour la table des descripteurs
globaux. La longueur de chaque descripteur étant de 8 Octets, il y a donc 64 kilo-Octets /8 Octets soit 8192
descripteurs par table.
Une table de descripteurs globaux contenant elle aussi 8192 descripteurs de tables de descripteurs lo-
caux et qu’eux même contiennent à chaque fois 8192 descripteurs de segments de 64 kilo-Octets maximum,
on obtient une mémoire virtuelle maximale de :
8192 * 8192 * 64k = 1 Giga-Octets pour le 80286
au lieu de 16 Mega-Octets de mémoire physique !

15.5 Les mécanismes de protection mémoire ou les Niveaux de pri-


vilège
le mode protégé, le microprocesseur possède un processus de protection mémoire très efficace,
D ANS
qui permet qu’un programme lambda ne puisse accéder à des segments mémoires de données qui ne
lui sont pas affectés !
Chaque segment de code ou de données à ce qu’on appelle un niveau de privilège de 0 à 33 . Ce niveau
est codé dans les 2 bits de poids faible du mot sélecteur de segment (RPL) voir format d’une adresse
virtuelle.

F IG . 15.2 – Le diagramme de répartition des niveaux de privilège

– Pour les segments de données : la règle s’appliquant aux segments de données en général, est qu’un
segment ne peut accéder qu’aux segments de privilège égal ou inférieur
Les deux figures ci-dessous montre les accès aux segments de données
3 Nous verrons ce principe dans le chapitre intitulé La communication avec le matériel.

80
F IG . 15.3 – Les accès autorisés

F IG . 15.4 – Les accès interdits

Pour les segments de codes : L’accès au niveau égal est autorisé, sinon aucune tâche ne pourrait se
composer de plusieurs segments. L’accès au niveau inférieur est interdit, afin d’augmenter la robustesse
des programmes. Cependant, les appels de fonction du système d’exploitation par une tâche sont autorisés,
c’est ce que l’on appelle des " Call-Gates " (portes d’appel).
Le système d’exploitation ne peut quant à lui appeler des routines appartenant à une application quel-
conque !
Les registres pointeurs sur tables de description (gdtr, ldtr, idtr et tr), qui ont une importance détermi-
nante dans la gestion de la mémoire virtuelle et la commutation des tâches, ne sont accessibles qu’au noyau
du système d’exploitation au niveau de privilège 0.

15.6 Le changement de tâche


multi tâche n’est en faite qu’une commutation extrêmement rapide entre plusieurs tâches, ce qui
L E
donne l’illusion d’une exécution simultanée. Pour passer d’une tâche à l’autre, il faut sauvegarder
l’environnement et les registres du microprocesseur. Les microprocesseurs 80286 et plus supportent le pro-
cessus de sauvegarde et de récupération des registres au niveau du matériel, donc le système d’exploitation
n’a pas à s’en charger et cela est plus rapide.
Les registres du microprocesseur sont sauvegardés dans un segment, de 44 Octets soit 352 bits, nommé
Segment d’Etat de Tâche (TSS). De même que les descripteurs de tables de descripteurs locaux, ils font
partie des segments systèmes.
Il y a 1 segment d’état de tâche par tâche active.

81
15.7 Les exceptions et les interruptions
le mode protégé, les microprocesseurs 80286 et plus connaissent les interruptions logiciels et
D ANS
matériels du mode réel du 8086 et en plus les exceptions. Les exceptions ne sont pas appelés par
le logiciel ou par un dispositif périphérique, mais directement par le microprocesseur. Une exception est
déclenchée chaque fois que la tâche en cours déclenche une action avec laquelle le microprocesseur n’est
pas d’accord. (exemple : écriture en zone de données dont l’octet d’état du descripteur est tel que la dite
zone est en mode lecture.)
Contrairement au mode réel, il n’y a pas de table de vecteurs d’interruptions. C’est le registre idtr (In-
terrupt Descriptor Table Register) qui contient l’adresse d’une table contenant sous la forme de F+GATES,
les adresses des points d’entrées dans les routines d’interruptions et d’exceptions.
Il peut y avoir une table par tâche.

15.8 Le mode Protégé des microprocesseurs 386 et 486


fonctionnement des microprocesseurs 386 et du 486 n’est pas fondamentalement différent de celui
L E
du 286 vu précédemment. Comme pour le mode réel, les modifications les plus importantes sont : la
gestion de registres 32 bits, la gestion de pages mémoire de 4 kilo-Octets (mémoire paginée) et la possibilité
d’inhiber séparément certains ports d’entrée-sortie.

15.8.1 Les registres des 386 et 486


Ils sont passés de 16 bits à 32 bits sauf ldtr et tr, leur nombre à augmenté de :
– 2 registres de segments fs et gs, qui comme es viennent faciliter les accès à la mémoire de données.
– 4 registres de commande cr0 à cr3, dont l’usage est réservé au système d’exploitation, pour le méca-
nisme de pagination.
– 8 registres de déboggage dr0 à dr7, il fallait s’en douter, avec des programmes devenant de plus en
plus complexes. Grâce à eux, il est possible de poser quatre points d’arrêts qui ne se déclencheront
pas seulement sur une instruction donnée mais également en cas d’accès à une mémoire fixée à
l’avance. Ce principe permet aux logiciels de débbogage de mieux gérer la mémoire.

15.8.2 La structure des descripteurs de segments


Nous avions vu pour le 286 que les deux Octets de poids forts étaient réservés au 386, nous allons voir
leur fonction. Ce mot de 16 bits est en fait coupé en deux Octets,
– L’Octet de poids fort représente les bits 24 à 31 de l’adresse de base, donc elle est codée sur 32 bits.
– L’Octet de poids faible :
– Les bits 0 à 4 représentent les bits 16 à 19 de la longueur du segment,
– les bits 4 et 6 sont inutilisés,
– Le bit 5 est toujours à 0
– Le bit 7
– Vaut 1 si on est en mode paginé,
– 0 dans le cas contraire.
Donc on peut en déduire la taille des mémoires

Mémoire virtuelle

8192*8192 *1 Méga-Octets = 64 Téra-Octets


pour le microprocesseur 80386
contre 32 Giga-Octets de mémoire physique !

82
15.8.3 La pagination et la mémoire virtuelle
Nous avons vu que pour le microprocesseur 286 en mode protégé, que chaque segment ne vaut plus
64 kilo-Octets mais est compris entre 1 Octet et 64 kilo-Octets. Si pendant l’exécution d’une tâche, le
microprocesseur rencontre un segment absent, il déclenche une exception qui est interceptée par le système
d’exploitation et est interprétée comme une demande de chargement de segment.
L’inconvénient de cette méthode, est que les blocs de mémoire à importer et à exporter ont des tailles
différentes. Il est possible que seule une petite partie de ce segment soit nécessaire, et que dans l’instant
qui suit elle doive être retirée de la mémoire en raison d’une commutation de tâche. Pourtant, l’intégralité
du segment est expatrié avant d’être rechargé. La taille du fichier d’échange, sur le disque dur, croît sans
cesse. De même pour la mémoire physique, le gestionnaire de mémoire virtuelle est sans cesse contraint de
rapprocher les segments. Même si ce mécanisme est transparent pour les différentes tâches, il ne reste pas
moins vrai qu’il gaspille du temps d’exécution, donc ralentit la machine.
La solution est donc de rendre à nouveau la taille des blocs mémoires en circulation constante. Ce
processus doit se trouver en retrait par rapport à la segmentation, donc à un niveau plus bas qui le rend
transparent. C’est ce que font les microprocesseurs 386 et plus qui implémentent un mécanisme de pagina-
tion reposant sur des blocs de 4 kilo-octets.
Le principe est le suivant :

F IG . 15.5 – Les adresses virtuelles, linéaire et physique

La mise en service de blocs de mémoire de taille constante ne simplifie pas seulement la gestion du
fichier d’échange. L’accroissement de ce fichier n’est plus incessant : lorsqu’une page de 4 kilo-Octets se
libère, une autre peut prendre sa place puisqu’elle a la même taille. Par ailleurs seules des pages limitées
à 4 kilo-Octets vont circuler, et non plus des segments entiers pouvant théoriquement aller jusqu’à 1 giga-
Octets.
Vous pourrez trouver dans la Bible du PC, des explications plus approfondies sur le fonctionnement de
la mémoire paginée.

15.8.4 Des modes d’adressage plus souples


’ INTRODUCTION du microprocesseur 386 a permis une extension des modes d’adressage, le micro-
L processeur se rapprochant de ses concurrents de Motorola notamment. En mode réel comme en mode
protégé, tous les registres généraux peuvent désormais servir de registres de Base ou de registres d’Index,
on n’est plus limité à certaines combinaisons de si, di et bp.
L’un des registres d’index peut être multiplié automatiquement par le facteur 2, 4, ou 8 pour permettre
un accès plus rapide aux tables de mots, doubles et quadruples mots.
Un Offset de 8 ou 32 bits peut encore être ajouté à l’ensemble.
Les modes d’adressage du microprocesseur 80386.

83
F IG . 15.6 – :Les modes d’adressage du 80386

15.9 Passer du mode Réel au mode protégé


programme source ci-dessous montre comment un certain Linus Torwalds à fait pour faire passer le
L E
microprocesseur 80386 du mode réel au mode protégé.
1 /*
2 *
3 * Trampoline.S Derived from Setup.S by Linus Torvalds
4 *
5 * 4 Jan 1997 Michael Chastain: changed to gnu as.
6 *
7 * Entry: CS:IP point to the start of our code, we are
8 * in real mode with no stack, but the rest of the
9 * trampoline page to make our stack and everything else
10 * is a mystery.
11 *
12 * In fact we don’t actually need a stack so we don’t
13 * set one up.
14 *
15 * We jump into the boot/compressed/head.S code. So you’d
16 * better be running a compressed kernel image or you
17 * won’t get very far.
18 *
19 * On entry to trampoline_data, the processor is in real mode
20 * with 16-bit addressing and 16-bit data. CS has some value
21 * and IP is zero. Thus, data addresses need to be absolute
22 * (no relocation) and are taken with regard to r_base.
23 *
24 * If you work on this file, check the object module with objdump
25 * --full-contents --reloc to make sure there are no relocation
26 * entries except for the gdt one..
27 */
28
29 #include <linux/linkage.h>
30 #include <asm/segment.h>
31 #include <asm/page.h>

84
32
33 .data
34
35 .code16
36
37 ENTRY(trampoline_data)
38 r_base = .
39 wbinvd # Needed for NUMA-Q should be harmless for others
40 mov %cs, %ax # Code and data in the same place
41 mov %ax, %ds
42
43 mov $1, %bx # Flag an SMP trampoline
44 cli # We should be safe anyway
45
46 movl $0xA5A5A5A5, trampoline_data - r_base
47 # write marker for master knows we’re running
48
49 lidt idt_48 - r_base # load idt with 0, 0
50 lgdt gdt_48 - r_base # load gdt with whatever is appropriate
51
52 xor %ax, %ax
53 inc %ax # protected mode (PE) bit
54 lmsw %ax # into protected mode
55 jmp flush_instr
56 flush_instr:
57 ljmpl $__KERNEL_CS, $0x00100000
58 # jump to startup_32 in arch/i386/kernel/head.S
59
60 idt_48:
61 .word 0 # idt limit = 0
62 .word 0, 0 # idt base = 0L
63
64 #
65 # NOTE: here we actually use CPU#0’s GDT - but that is OK, we reload
66 # the proper GDT shortly after booting up the secondary CPUs.
67 #
68
69 gdt_48:
70 .word 0x0800 # gdt limit = 2048, 256 GDT entries
71 .long cpu_gdt_table-__PAGE_OFFSET # gdt base = gdt (first SMP CPU)
72
73 .globl SYMBOL_NAME(trampoline_end)
74 SYMBOL_NAME_LABEL(trampoline_end)
Comment trouvez-vous le nom de ce programme ?

15.10 Conclusion
qu’ils s’affairaient à mettre au point le 80286, les développeurs d’Intel misaient sur le succès
A LORS
rapide du mode Protégé et la mort lente mais " programmée " du mode réel. Mais cela était sans
compter sur un "bug " de taille, le système d’exploitation DOS (victime de son succès). Pendant la concep-
tion du 80386, les idées durent se plier à l’implacable entêtement des faits, autrement dit à la pérennité de
ce “fameux” et sacré système d’exploitation DOS.

85
Mais que faire ?4

15.11 Post-Scriptum
mode virtuel des processeurs 80386 et plus le V86 : il constitue la symbiose entre le mode Réel et
L E
le mode Protégé, il est présent dans de nombreux types d’extensions système. Il va de l’émulateur
d’EMS, aux extensions multitâche en passant par la boite DOS de Windows. Le système apparaît, pour
un programme tournant en mode Virtuel, comme un µP fonctionnant en mode Réel, mais ayant en arrière
plan (nous y voilà), la gestion de la mémoire, la commutation des tâches et les règles de privilège du mode
protégé qui restent actives.
En mode V86, un programme exécuté comme une tâche autonome ne voit rien aux mécanismes de
protection. Il a les yeux fixés sur son espace mémoire de 1 méga-octets qui est adressé selon les règles du
mode Réel, à savoir Segment+Offset*16. Pour la tâche V86, les contenus des registres de segment sont
véritablement des adresses de segments et non des sélecteurs comme en mode Protégé. Un programme
peut donc charger n’importe quelle valeur dans un registre de segment sans craindre de déclencher une
exception ce qui engendre de nombreux plantages dans certains systèmes d’exploitation. . .
Pour de plus amples renseignements à ce sujet, je vous invite à lire les pages 1237 à 1326 de la Bible
du PC 5ème édition.

4 Passer à Linux :)

86
Chapitre 16

La Communication avec le Matériel

16.1 Introduction
Nous avons vu dans un cours précédent que le microprocesseur 8086 pouvait adresser 220 adresses, soit
1 mega adresses mémoires. Il peut aussi communiquer avec des ports d’entrée-sortie identifiés eux aussi
par une adresse dont la valeur est comprise entre 000016et f f f f16(65 536 soit 216 ).
Les fils d’adresses A0 à A15 étant les mêmes pour la mémoire et les ports d’entrée-sortie, il a fallu que
le fabriquant trouve une solution pour accéder à l’un (Mémoire) sans accéder à l’autre (E/S).
Rappel : Pour accéder à une mémoire, on utilise l’instruction mov.

16.2 Accès aux ports d’entrée-sortie


Pour communiquer avec les ports, le microprocesseur se sert donc des bus d’adresses et de données
comme pour un accès classique à la mémoire. Il commence par envoyer sur une ligne de son bus de
commande un signal indiquant qu’il ne va pas s’adresser à la mémoire mais aux ports d’entrée-sortie.
Ensuite il dépose sur son bus d’adresses les valeurs des 16 bits A0 à A15 correspondant au port qu’il désire
adresser, et attend que le port concerné lui "réponde" et ensuite il envoie la donnée de 8 ou 16 bits sur le
bus de données.
La même chose se passe en sens inverse pour la lecture, le contenu du port est envoyé au microproces-
seur, sur la requête de ce dernier bien sur, par le même mécanisme.
Les moyens : Pour ceci, le microprocesseur 8086 dispose de deux instructions qui permettent
1. de récupérer des données venant du port : in
2. d’envoyer des données vers le port : out

16.3 La syntaxe
in <Adresse du port>,<Accumulateur>
out <Accumulateur>,<Adresse du port>
avec
– Accumulateur qui doit être le registre al (8bits) ou le registre ax (16bits)

– Adresse du port qui doit être une adresse absolue sur 8 bits d’un port ou le registre dx lorsque l’on
désire adresser le port sur 16 bits.
Exemple

87
inb $60h, %al #Acquisition du code de scrutation du clavier
inb %dx,%al #@ du port est définie par DX
movw $0x03b4,%dx #@ de la carte vidéo monochrome
outb %al, %dx # Transmettre à la carte vidéo monochrome
outb %al,$0x64 # Port de sortie du Clavier
outw %ax,%dx # Afficher le mot.

16.4 Les adresses des ports d’entrée-sortie


Ce tableau montre les adresses des ports d’entrée-sortie des premiers PC. Ces données existent toujours
pour une question de compatibilité.

Nom du périphérique Les adresses


Contrôleur DMA (80237A-5) 000-01F
Contrôleur d’interruption (8259A) 020-03F
Temporisateur 040-05F
Clavier (8048 ou 8042) 060-06F
Horloge Temps Réel (MC146818) 070-07F
Registre de page DMA 080-09F
Contrôleur d’interruption N˚2 (8259A) 0A0-0BF
Contrôleur DMA N˚2 (80237A-5) 0C0-0DF
Coprocesseur Mathématique 0F0-0F1
Coprocesseur Mathématique 0F8-0FF
Contrôleur de disque dur 1F0-1F8
Manette de jeux (Joystick) 200-207
La seconde interface parallèle 278-27F
La seconde interface série 2F8-2FF
Carte de prototype 300-31F
Carte de réseau 360-36F
La première interface parallèle 378-37F
Carte d’écran monochrome 3B0-3BF
Carte vidéo couleur/graphique 3D0-3DF
Contrôleur de disquette 3F0-3F7
La première interface série 3F8-3FF

Sur les ordinateurs plus récents on dispose d’un espace d’entrée sortie bien plus conséquent1, je ne vais
pas refaire un tableau qui serait assez long et très fastidieux à lire. . .
Je vous propose donc de jeter un œil sur le résultat de la commande
cat /proc/ioports
réalisé sur un micro-ordinateur quelconque sous le système d’exploitation Linux.

Resultat de la commande
cat /proc/ioports
sur un ordinateur moderne...

0000-001f : dma1
0020-003f : pic1
0040-005f : timer
0060-006f : keyboard
0070-007f : rtc
1 ll faut croire que les 65 536 adresses du premier PC ne sont plus suffisantes. . .

88
0080-008f : dma page reg
00a0-00bf : pic2
00c0-00df : dma2
00f0-00ff : fpu
0170-0177 : ide1
01f0-01f7 : ide0
0376-0376 : ide1
0378-037a : parport0
037b-037f : parport0
03c0-03df : vga+
03f6-03f6 : ide0
0cf8-0cff : PCI conf1
1800-1807 : Intel Corp. 82852/855GM Integrated Graphics Device
1810-181f : Intel Corp. 82801DBM Ultra ATA Storage Controller
1810-1817 : ide0
1818-181f : ide1
1820-183f : Intel Corp. 82801DB USB (Hub #1)
1820-183f : usb-uhci
1840-185f : Intel Corp. 82801DB USB (Hub #2)
1840-185f : usb-uhci
1860-187f : Intel Corp. 82801DB USB (Hub #3)
1860-187f : usb-uhci
1880-189f : Intel Corp. 82801DB/DBM SMBus Controller
18c0-18ff : Intel Corp. 82801DB AC’97 Audio Controller
18c0-18ff : Intel ICH4
1c00-1cff : Intel Corp. 82801DB AC’97 Audio Controller
1c00-1cff : Intel ICH4
2000-207f : Intel Corp. 82801DB AC’97 Modem Controller
2400-24ff : Intel Corp. 82801DB AC’97 Modem Controller
3000-30ff : Realtek Semiconductor Co., Ltd. RTL-8139/8139C/8139C+

16.5 Les droits


Les 2 définitions ci-dessous sont des extraits des man des 2 appels systèmes que l’on peut utiliser en
langage d’assemblage comme en C afin de pouvoir accéder aux entrées sorties sans passer par les fonctions
de hauts niveaux.
L’appel système ioperm

ioperm - Positionner les autorisations d’entrée/sortie sur les ports.

Ioperm positionne les bits de permission d’accès du processus


aux ports.
L’utilisation de ioperm nécessite les privilèges de Super-User.

Seuls les 0x3ff premiers ports d’entrée/sortie peuvent être indiques de


cette manière. Pour d’autres ports, il faut utiliser la fonction iopl.

Les permission ne sont pas héritées par le processus fils durant un fork,
par contre elles le sont lors d’un exec.
Ceci permet de donner des autorisations d’accès à des tâches non-privilégiées.
ioperm renvoie 0 s’il réussit, ou -1 s’il échoue, auquel cas errno contient
le code d’erreur.

89
ioperm est spécifique a Linux et ne doit pas être utilisé dans
des programmes conçus pour être portables.

L’appel système iopl

iopl change le niveau de privilège pour les entrées/sorties du processus


courant, en utilisant la valeur spécifiée dans level.

Cette fonction est indispensable pour permettre aux serveurs X compatibles


8514 de fonctionner sous Linux. Comme ces serveurs X ont besoin de l’accès
aux 65536 ports d’entrée/sortie, la fonction ioperm ne serait pas suffisante.

En plus de disposer d’un accès illimité aux ports d’entree/sortie, un processus


tournant à un niveau de privilège élevé pourra également inhiber les interruptions.
Ceci risque d’engendrer un plantage du système, et est fortement déconseillé.

Les permissions sont héritées aussi bien par fork que par exec.

Le niveau de privilège d’entrée/sortie pour un utilisateur normal vaut 0.


iopl renvoie 0 s’il réussit, ou -1 s’il échoue, auquel cas errno contient
le code d’erreur.

iopl est spécifique à Linux et ne doit pas être utilisé dans


des programmes conçus pour être portables.

Vous pouvez les consulter plus en détail en tapant les commandes


man ioperm
man iopl
sous Linux

16.6 Exemple de programme


Le code source ci-dessous montre comment on peut faire jouer do ré mi fa sol la si do par le haut-parleur
du PC, à condition que ce dernier soit activé.

1 .align 4
2 .data
3 Message:
4 .string "valeur de la note : %s %d \n"
5 Nom_notes:
6 .string "do ","re ","mi ","fa ","sol","la ","si ","do "
7 Sav_HP:
8 .byte 0
9 #pour l’octave 3
10 Notes:
11 .word 9121,8126,7239,6449,5746,5423,5119,4831
12
13 #;***********************************************************
14 .text
15 .align 4
16 .globl main
17 main:
18 pushl %ebp

90
19 movl %esp,%ebp
20 pusha
21
22 call Initialisation
23
24 xorl %ebx,%ebx #Initialisation de l’index
25 movl $8,%ecx #8 notes do ré mi fa sol la si do
26 Note_suivante:
27 movw Notes(%ebx),%ax #fréquence
28
29 pusha
30
31 pushl %eax #la valeur de la note
32
33 movl %ebx,%eax
34 shll $1,%eax #%eax*2
35 addl $Nom_notes,%eax
36 pushl %eax #la note
37 pushl $Message
38 call printf
39 addl $12,%esp
40 popa
41
42 outb %al,$0x42 #mise dans le Timer
43 movb %ah,%al
44 outb %al,$0x42
45
46 movl $0x61,%edx #@ du HP
47 inb %dx,%al #on récupére son état
48 movb %al,Sav_HP #On le sauve
49 orb $3,%al #On positionne ses 2 bits de poids faible à 1
50 outb %al,%dx #Ici le son doit se produire
51
52 call Tempo #durée de la note
53
54 incl %ebx #notes suivantes
55 incl %ebx #inc 2 fois car 1mot=2 octets
56 loop Note_suivante #et la mémoire est gérée octet par octet !
57
58 call Stop_son
59
60 popa
61 movl %ebp,%esp
62 popl %ebp
63 ret
64
65 #;***********************************************************
66 Stop_son:
67 pushl %ebp
68 movl %esp,%ebp
69
70 movl $0x61,%edx #Pour arréter le son
71 movb Sav_HP,%al

91
72 andb $0b11111100,%al
73 outb %al,%dx #Ici le son doit s’arréter
74
75 movl %ebp,%esp
76 popl %ebp
77 ret
78
79
80 #;***********************************************************
81 Tempo:
82 pushl %ebp
83 movl %esp,%ebp
84
85 pushl %ecx
86 movl $0x5ffffff,%ecx
87 Boucle:
88 loop Boucle
89 popl %ecx
90
91 movl %ebp,%esp
92 popl %ebp
93 ret
94 #;***********************************************************
95 Initialisation:
96 pushl %ebp
97 movl %esp,%ebp
98
99 pushl $1 # Permission pour 61h : HP
100 pushl $1
101 pushl $0x61
102 call ioperm
103 addl $12,%esp
104
105 pushl $1 # Permission pour 42h et 43h
106 pushl $2 #42h
107 pushl $0x42
108 call ioperm
109 addl $12,%esp
110
111 movb $182,%al #Pour atteindre le temporisateur
112 movw $0x43,%dx
113 outb %al,%dx
114
115 movl %ebp,%esp
116 popl %ebp
117 ret
118 #;***********************************************************
119

On peut constater dans le source de ce programme aux lignes


– 42 à 50 l’accès aux ports d’entrée-sortie.
– 99 à 109 les demandes de droits sur les entrées-sorties.

92
16.7 Conclusion
Ce chapitre nous a montré les deux espaces mémoire des microprocesseurs de la famille iAPX, il est
loin d’être complet, mais il suffit pour comprendre les principes.
Dans les systèmes d’exploitation actuels, il n’y a aucun intérêt à vouloir accéder directement aux ports
d’entrée-sortie, il vaut mieux utiliser les appels système sous Linux ou les interruptions du dos sous Win-
dows.
De toutes manières, vous ne pouvez avoir accès à la programmation de ces ports d’entrées sorties si
vous n’êtes pas l’administrateur de l’ordinateur.
Nous verrons en TP la programmation des entrées sorties, sur des machines ou vous serez root2 .

2 Non non, vous n’aurez pas le droit de tout faire

93
Index

Symbols R
3Dnow, MMX, SIMD . . . . . . . . . . . . . . . . . . . . . . . . 63 registre . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
routine d’interruption, handler . . . . . . . . . . . . . . . . . 66
A
adresse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 S
Alan Turing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 SIMD, 3Dnow, MMX . . . . . . . . . . . . . . . . . . . . . . . . 63
APIC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 stack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
assembleur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
U
B UC, CPU . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
byte, Octet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
V
C Vecteur d’interruption . . . . . . . . . . . . . . . . . . . . . . . . 71
codes mnémoniques . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
compilateur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
compilation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
computing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
Contrôleur d’Interruption . . . . . . . . . . . . . . . . . . . . . 67
CPU, UC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

D
données . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1

F
FIFO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

H
handler, routine d’interruption . . . . . . . . . . . . . . . . . 66

I
interpréteur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
interruption . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
IRQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67

L
langage d’assemblage . . . . . . . . . . . . . . . . . . . . . . . . . 9

M
MMX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
MMX, 3Dnow, SIMD . . . . . . . . . . . . . . . . . . . . . . . . 63

O
Octet, byte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

P
pile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
port E/S . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87

94

Vous aimerez peut-être aussi