Software
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
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
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
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
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
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
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
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.
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 .
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.
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"
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
12
Chapitre 2
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
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
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.
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.
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
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
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.
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.
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).
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
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.
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.
20
Chapitre 4
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
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
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).
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.
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 #.
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.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.
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
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.
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.
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.
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
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)
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.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
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
36
[Link] Initialisation d’un tableau avec une seule valeur
Exemple
Tableau : .space 4,25 # stocke 4 fois 25 à l’adresse Tableau
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.
Remarque : Pour les microprocesseurs 386 et suivants, il faut remplacer respectivement les registres
ax à bp par les registres eax à ebp.
38
Chapitre 8
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.
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
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
/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
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
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.
44
F IG . 8.3 – Décalage logique à droite
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.
46
Chapitre 9
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.
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.
– 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.
– 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 !
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.
– 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
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.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
52
decl %ecx
jnz lettre_suivante
par l’instruction suivante
loop Lettre_suivante
– 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
53
Chapitre 11
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".
.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
54
.long 0
.long 1
.long 2
.long 3
.long 4
Il est possible d’imbriquer les blocs de répétition.
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.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
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.
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.
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
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).
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).
#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
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.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
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.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 */
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
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.
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.
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
03 00C-00F CPU : B REAK POINT ATTEINT 21 084-087 DOS : A PPELER FONCTIONS DOS
0A 028-02B IRQ2 : 2nd 8259 (AT UNIQUEMENT ) 28-3F 0A0-0FF R ÉSERVÉ DIFFÉRENTES FONCTIONS
MÉMOITE D E LA RAM
13 04C-04F BIOS : DISQUETTES / DISQUE DUR 70 1C0-1C3 IRQ8 : H ORLOGE TEMPS RÉEL (AT)
1B 06C-06F TOUCHE B REAK ACTIONNÉE 78-7F 1E0-1FF U TILISÉS PAR L’ INTERPRÉTEUR BASIC
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.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.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.
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.
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
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.
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
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
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.
– 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
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.
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.
Mémoire virtuelle
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 :
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.
83
F IG . 15.6 – :Les modes d’adressage du 80386
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
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.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.
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+
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.
Les permissions sont héritées aussi bien par fork que par exec.
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
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 .
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