Vous êtes sur la page 1sur 26

17/11/2017

Introduction à l’Assembleur

Par Mohssin Aoutoul


Mohssin.aoutoul@gmail.com

Introduction
Tous les langages de programmation dits « évolués »
(«structurés», «orientés objet», etc.), qu'ils soient compilés ou
interprétés doivent d'une manière ou d'une autre être «traduits»
en langage machine avant de pouvoir être exécutés par un
ordinateur
• Avantage des langage évolués:
Développements des logiciels complexes
Conception, lisibilité, maintenance, portabilité…
• Le côté déplaisant
Ils cachent les limitations de la machine:
1. sous-exploitation des capacités du processeur (processeur
64 bits: nouveaux jeux d’instruction, e.g SIMD (16 opération
arithmétique à la fois) mais rares les compilateurs exploitant
ces instructions et les langages qui en tirent profit
SIMD: Single Instruction on Multiple Data ( instruction unique, données multiples)

1
17/11/2017

Introduction Cont.

Les processeurs 64 bits vendus avec des OS 32 bits!


2. surestimation des capacités

S’il est impossible d’écrire des programmes en langage machine,


il est possible de les écrire en langage assembleur (version
légèrement « humanisée »)
Connaitre les rudiments de la programmation en
assembleur peut donc donner des atouts considérables pour la
compréhension et la maitrise de tous les autres langages de
programmation.

Rappels sur la structure des ordinateurs

• Les cases mémoires


La mémoire est découpée en particules élémentaires: bits
prenant deux valeurs possibles (binaire) (différentes
interprétations…)
Pour augmenter la capacité de représentations des bits, la
mémoire d’un ordinateur est structurée comme suit: une suite
de cases mémoires qui sont à leurs tours des suites de bits

1 bit Case
mémoire

2
17/11/2017

Rappels sur la structure des ordinateurs, Cont.


• Nombre de bit et capacité de représentation
– En décimal, une particule = 10 valeurs (0-9)
– n particules = 10n valeurs possibles
– En représentation binaire, une particule= deux
valeurs possibles (0-1)
– n particules (bits) = 2n valeurs possibles (0 – 2n-1)
– Pour représenter un objet prenant X valeurs il faut
Y bits tq: X ≤ 2Y
– Z objets avec X valeurs: Y bits tq XZ ≤ 2Y
NB: impossible de représenter complètement l'espace des nombres entiers,
rationnels, réels, complexes, etc. (mémoire limitée)

Rappels sur la structure des ordinateurs, Cont.

• La base hexadécimale
La base hexadécimale est utilisée pour représenter des données
pour :
des raisons de lisibilité
Faciliter la représentation des données: un nombre binaire de 4
bits peut être représenté par un chiffre hexadécimal (0, 1, 2, 3, 4,
5, 6, 7, 8, 9, A, B, C, D, E, F) (e.g (1111)B = (F)X = (15)D)
• Sous-parties du contenu d’une case mémoire
Partie haute de 16 bits
Partie basse de 12 bits

F9E8D7C6
Partie haute de 8 bits

3
17/11/2017

Rappels: organisation de la mémoire

• Tailles des cases mémoires les plus utilisées


1. Octet (byte): case mémoire de 8 bits
2. Le mot de 16 bits: suite de deux Octets
3. Le mot de 24 bits: suite de 3 octets
4. Le mot de 32 bits: suite de 4 octets
5. Le mot de 64 bits: suite de 8 octets

Rappels: adresses des cases moires


• Chaque particule en mémoire doit avoir son adresse unique,
Exemple: X adresses à X bits demande un espace mémoire de Y
bit tq: X ≤ 2Y (e.g 4 adresses à 4 bits: nécessite 2 bits)
• L’espace mémoire nécessaire est inversement proportionnel à la
taille minimale des case mémoires adressable
• Cette taille minimale est, dans la plupart des architecture, est de
8 bit (octet)
• Chaque octet dans la mémoire possède une adresse physique
unique
• 1octet peux générer 256 (28) adresses différentes d’octets
• 4 octets (32 bits): on peut accéder à 4 Go (1Ko=210 octet…)
• Les processeur peuvent manipuler des adresses sur 64 bits et
donc peuvent gérer un espace adressable de 264 Octet (environ
17x109 Go)

4
17/11/2017

Programme en langage machine

• Suite d’instructions-machine,
petit programme en langage machine
chaque instruction-machine est totalement, écrit en binaire avec une
une suite de bits contenant les mémoire découpée en octets

informations nécessaire pour


l’exécution de l’instruction
• Les instruction stockées dans la
mémoire sont accessibles par
blocks: 1 octet (8 bits), 16 bits
(un mot), 32 bits( mot long ) et
64 bits et rarement 24 bits,

Compilation d’un programme source

5
17/11/2017

gcc: GNU
Compiler
Collection

Compilation d’un programme en C: exemple


Difficile de
connaitre quel
code pour quelle
Le même programme compilé
Petit programme écrit en en instructions codés en IA-32
instruction
langage C (fichier source) (fichier objet) (IA: Intel Archit.)

Même programme mais écrit


en langage assembleur
IA-32 (short for "Intel
Mais c’est quoi Architecture, 32-bit“:
push, mov, sub, 32-bit version of
the x86 instruction set
call, %esp..etc. ? architecture (ISA). The
first incarnation of x86
that supports 32-bit
computing, 1985

6
17/11/2017

Programme en langage assembleur

L’assembleur permet de rendre le programme en langage machine plus


visible:
• Chaque ligne d'assembleur contient une seule instruction, l'adresse
d'une instruction est essentiellement constituée par son numéro de
ligne.
• Le programmeur peut donner des noms aux adresses importantes
pour lui.
• Les instructions s‘écrivent sous la forme « mnémonique +
suite_d'opérandes »
• la mnémonique est un mot qui rappelle le rôle de l’instruction
Exemple: MOV Source, Destination # va copier la donnée qui se trouve à
l’adresse Source dans l’adresse Destination
La lettre # pour indiquer que cet un commentaire dans certain types de
langages assembleurs

Les codes assembleurs

• Différents langages assembleurs utilisent différents


mnémoniques pour représenter des codes d'instruction. Alors
que les tendances ont émergé pour normaliser les
mnémoniques assembleur, il y a encore une grande variété de
codes mnémoniques, non seulement entre les familles de
processeurs, mais même entre les assembleurs utilisés pour
les processeur des mêmes groupes de jeux d’instructions.

7
17/11/2017

Programme en langage assembleur: exemple

al (AL): registre de
travail en architecture
x86, la lettre ‘L’ veut
dire du poids faible
(Low)

Les Sections en langage assembleur


Trois sections:
.data
.bss
.text
Sections des données: .data
• La section de données (.data) du programme est l'endroit le plus
commun pour définir les éléments de données. La section de
données définit emplacements spécifiques en mémoire où les
objets sont stockés,
• La section de données est déclarée en utilisant la directive .data.
Tous les éléments de données déclarés dans cette section sont
réservées dans la mémoire et peuvent être lues ou écrites par des
instructions dans le programme en langage assembleur.

8
17/11/2017

Section de donnée (.data) Cont.


• Deux objets sont nécessaires pour définir un élément de données dans la
section de données (.data): une étiquette (tag) et une directive (e.g
.byte):
.data
Exemple:
msg: .ascii “Bonjour tout le monde\n”

.ascii Texte, chaine de caractères


.asciz Texte/chaine de caractères terminée par NUL
.byte Une valeur en un octet
.double Réel à double précision
.float / .single Réel simple
.int Entier codé en 4 octets (32 bits)
.long Entier codé en 4 octets (32 bits)
.octa / .short Entier en deux octets (16 bits)
.quad Entier codé en 8 octet s
.single

Instruction en assembleur

Tag (Label): Mnémonique Operande(s) #Comment.

Op1: source, op2: destination

exemple
mov $10, %al #déplacer la valeur 10 au registre AL

Langage assembleur:
mov A, % eax #déplacer la valeur de A au registre eax
En langage haut niveau:
mul B #multiplie B par la valeur stokée en eax
D = A * B + 10
add $10, %eax #ajouter la valeur 10 à eax
mov %eax, D #déplacer la valeur stockée dans EAX vers D

9
17/11/2017

Types d’opérandes en assembleur

• Des tags (ou bien des étiquettes) comme res et nb1


• constante entière comme $5 en base décimale ($0b010101
pour exprimer la valeur d'une constante en base binaire et
$0x9ABC01 pour la base hexadecimale)
• Un registre comme al ou eax, il le précéder par % pour le
distinguer d’une étiquette

Remarque:
Comme les opérations arithmétiques ne peuvent être réalisées
directement sur des emplacements en mémoire externe, les registres,
qui sont des emplacements de mémoire internes au processeur, sont
utilisés pour ces opérations.

Taille d’un opérande ou d’opération

• ‘b’ qui termine les mnémoniques mov et add indique la taille


en bits de l'opération a réaliser
• b: indique une opération sur 8 bits
• w: une opération sur 16 bits. Les emplacements contiennent
donc des mots (word).
• l: une opération sur des cases mémoires de 32 bits, des mots
longs (long words).
• d: même chose (double-word)
• q: indique une opération sur des cases mémoires de 64 bits,
(quad-word).

10
17/11/2017

Registre de travail (accumulateur)


AL: la partie basse (accumulator low) de 8 bits d'un registre de 16 bits nomme
AX (accumulator extended 0-15 bits).
AH: La partie haute de 8 bits de ce registre (accumulator high)
EAX: La version 32 bits de ce registre (extended accumulateur extended, bits
numérotés de 0 a 31)
RAX: La version 64 bits du même registre se nomme (0-63 bits)

NB: Les processeurs recents de la famille 80x86 possèdent 3 autres registres de


64 bits similaires a rax : rbx, rcx et rdx

Les registre de travail (famille x86)

Les quatre registres de travail sont principalement


utilisés pour stocker des résultats :
• EAX : registre accumulateur (accumulator register).
Utilisé pour les opérations arithmétiques et le
stockage de la valeur de retour des appels systèmes.
• EDX : registre de données (data register). Utilisé
pour les opérations arithmétiques et les opérations
d'entrée/sortie.
• ECX : registre compteur (counter register)
• EBX : registre de base (base register). Utilisé comme
pointeur de donnée (située dans DS en mode
segmenté).

11
17/11/2017

Les registre de travail (architecture x86), Cont.

Ces 4 registres 16 bits sont également décomposés en 8


registres de 8 bits :

• AL : octet de poids faible de AX


• AH : octet de poids fort de AX Les registres du
microprocesseur Intel 8086
• BL : octet de poids faible de BX
• BH : octet de poids fort de BX
• CL : octet de poids faible de CX
• CH : octet de poids fort de CX
• DL : octet de poids faible de DX
• DH : octet de poids fort de DX

Sens d’opérations: premier exemple

Ce code en assembleur est peut être la compilation du programme au-dessous écrit


en C/C++
char nb1 = 1, res = 0;
res = nb1 + 5;

12
17/11/2017

Débordements
• Comment peut-on savoir si le calcul a donne un résultat valide
?
• Exemple 1: 1 + 255 sur un octet pour le CPU est invalide
(résultat = (00000000)b = (0)d)
• Exemple2: -128 - 1 sur un octet donne 127 (invalide)
-128 = (10000000)b et -1 = (11111111)b
• le microprocesseur possède un registre special de 64 bits: le
registre d'etat RFLAGS (FLAG c.à.d. Drapeau en anglais). Une
partie de ces birts concerne les opérations arithmétiques
après une exécution.

Bits d’états pour les opérations arithmétiques

RFLAG état Signification


ZF (Zero Flag) indique si le résultat est nul (ZF=1) ou non nul (ZF=0)
SF (Sign Flag) indique si le résultat est positif (SF=0) ou négatif (SF=1)

PF (Parity Flag) indique que le résultat est pair (PF=1) ou impair (PF=0)

CF (Carry Flag) indique une retenue (CF=1) sur les entiers non signés
OF (Overflow indique un débordement (OF=1) sur les entiers signés
Flag)

CF: Ce drapeau prend la valeur 1 si une opération arithmétique génère une retenue
sur le bit le plus significatif (bit de poids fort). Le drapeau est désarmé dans les
autres cas. Ce drapeau indique ainsi une condition de débordement en arithmétique
entière non signée. Il est aussi utilisé pour l'arithmétique en précision multiple.

13
17/11/2017

Arithmétique binaire
Les règles de la soustraction
0-0=0
0 - 1 = (on emprunte "1" ce qui fait 10-1, on écrit "1" et on retient 1)
1-0=1
1-1=0
0 - 1 - 1 = (on emprunte "1" ce qui fait 10-1-1, on écrit "0" et on retient "1")
1-1-1=0-1
opérations de soustraction

Addition d'un nombre positif et un nombre négatif plus petit en valeur absolue

Addition d'un nombre positif et un nombre négatif plus grand en valeur absolue

Arithmétique binaire – Cont.


Addition de deux nombres négatifs

Addition de deux nombres égaux opposés

Le dépassement

Soustraction par complément à 2

14
17/11/2017

Flag de retenue CF

Exemples:
• 0b11111111 + 0b1 = 0b00000000, CF = 1
• 0b11111110 + 0b1 = 0b11111111, CF = 0
Remarque: si les opérandes sont des entiers non signés, le résultat
est valide si et seulement si CF =0 et il est invalide si et seulement
si CF = 1

Flag de débordement OF

• Si les opérandes sont des entiers signés, c'est le Flag OF qui


indiquera la validité du résultat:

Exemples:
0b11111111 + 0b1 = 0b00000000, CF=1 et OF=0
Si (0b11111111) est entier non signé donc (255 + 1) est invalide
dans N8 (la valeurs maximale est 28 – 1 = 255 gérée par le
microprocesseur)
Si (0b11111111) est un entier signé donc (-1 + 1) est valide dans
Z8 (la valeurs gérées sont de -128 à 127)

15
17/11/2017

Flag CF et OF, Exemples Cont.

• Exemple 2:
0b00000000 – 0b1 = 0b11111111 avec CF=1, mais OF=0

(0b00000000) est un entier signé donc (0 - 1) est invalide dans N8


(0b00000000) est un entier signé mais (0 - 1) est valide dans Z8

Exemple 3:
0b10000000 + 0b1 = 0b10000001 avec CF=0 et OF=0
Si (0b10000000) est entier non signé donc (128+ 1) est valide dans
N8 (0 – 255 valeurs)
Si (0b10000000) est un entier signé donc (-128 + 1) est valide dans
Z8 (-128 à 127)

Flag CF et OF, Exemples Cont.

• Exemple 4:
0b10000000 – 0b1 = 0b01111111, CF=0, mais OF =1

Si (0b10000000) = 128 (non signé) donc 128 - 1 est valide en N8


Si (0b10000000) = -128 (signé) donc -128 - 1 est invalide en Z8

Exemple 5:
0b01111111 + 0b1 = 0b10000000, CF=0, mais OF =1
(0b01111111)= 127d donc 127 + 1 est valide en N8 mais invalide
en Z8 (-128 à 127)

16
17/11/2017

Autres opérations arithmétiques


• Soustraction:
Syntaxe: sub source, destination
Où la source est soustraite de la destination avec le résultat
stocké dans la destination
Cette instruction provoque un
double calcul : le processeur fait
simultanément la soustraction une
fois en supposant les données
signées et une fois en les
supposant non signées.
Ainsi, le drapeau OF est levé si un
débordement survient lors de la
soustraction signée et le
drapeau CF est levé si une retenue
survient lors de la soustraction non
signée (résultat négatif)

Autres opérations arithmétiques


• Multiplication:
Syntaxe: mul source
Cette instruction multiplie le contenu de l'accumulateur
EAX (AX, AL suivant la taille de source) avec source. Le
résultat est placé dans l'accumulateur.
• si source est codée sur 1 octet, la multiplication est faite avec AL
et le résultat est codé sur 2 octets dans AX ;

• si source est codée sur 2 octets, la multiplication est faite avec


AX et le résultat est codé sur 4 octets dans la paire de registre
DX:AX ;

• si source est codée sur 4 octets, la multiplication est faite avec


EAX et le résultat est codé sur 8 octets dans la paire de registre
EDX:EAX.

17
17/11/2017

Multiplication des entiers non signés, Cont.

Taille de l’opérande source Destination de l’opérande Destination


8 bits AL AX
16 bits AX DX: AX
32 bits EAX EDX:EAX

Exemple de multiplication

Multiplication des entiers signés


• Multiplication signée:
Syntaxe: imul source OU imul source, destination

L'opérande source peut être un registre de 8, 16, ou 32 bits ou une


valeur en mémoire, et il est multiplié par l’opérande implicite situé
dans les registres AL, AX ou EAX (en fonction de la taille de
l'opérande de source). Le résultat est ensuite placé dans le registre
AX, la paire des registres DX: AX, ou dans la paire des registres
EDX: EAX
Le 2ème format vous permet de spécifier où le résultat de la
multiplication ira (au lieu d'être obligé d'utiliser l'AX et registres
DX).

18
17/11/2017

Multiplication des entiers signés, exemple

Division des entiers signés


• Division non signée:
Syntaxe: div opérande
le contenu qui peut être un registre de 8, 16, ou 32 bits ou une
valeur en mémoire est divisé par l’opérande
Si l'opérande de cette instruction est codée sur 8 bits, le contenu du registre AX
est divisé par l'opérande, le quotient est stocké dans AL et le reste dans AH.

Si l'opérande de cette instruction est codée sur 16 bits, l'entier défini par la paire
de registre DX:AX est divisé par l'opérande, le quotient est stocké dans AX et le
reste dans DX. Dans la pair de registre DX:AX, le poids faible est AX.

Si l'opérande de cette instruction est codée sur 32 bits, l'entier défini par la pair de
registre EDX:EAX est divisé par l'opérande, le quotient est stocké dans EAX et le
reste dans EDX.

19
17/11/2017

Division des entiers non signés, exemple

Incrémentation et décrémentation
• Incrémentation:
Syntaxe: inc opérande
• Décrémentation:
Syntaxe: dec opérande

inc additionne 1 à l’opérande

Dec prend 1 à l’opérande

20
17/11/2017

les instructions de
branchement

Registre RIP (Instruction Pointer)

le processeur exécute les instructions de tailles


différentes les unes après les autres. Pour cela, le
processeur dispose d'un registre spécial, nommé RIP
(64 bits) (EIP: 32 bits et IP: 16 bits) qui contient
l'adresse de l'instruction courante à exécuter. La valeur
contenue dans ce registre est automatiquement
augmentée lors de l'exécution d'une instruction afin
que le registre pointe sur l'instruction suivante

21
17/11/2017

Instructions agissant sur RIP

• branchement inconditionnel
Instruction jmp (sauter)
Elle permet de remplacer le contenu de RIP par une adresse
symbolique (Tag)
Syntaxe: jmp tag

Exemple:
debut: movl $2, %eax # 2 -> eax
jmp suite # on saute l’ instruction suivante
addl $2, %eax # cette instruction
# n'est pas exécutée
suite: movl %eax, %ebx # eax -> %ebx

Attention boucle infinie !


debut: jmp debut # mets l'adresse debut dans le registre RIP

Instructions agissant sur RIP, Cont.

• Branchements conditionnels
elles testent un ou plusieurs Flags du registre d‘état et en
fonction de leurs valeurs, effectuent le branchement ou
passent a l'instruction suivante, Le branchement est
effectué si la condition est remplie et qui est en fonction
des états des Flags ZF, CF et OF
Syntaxe: jz Tag (si résultat est nul ZF=1)
jnz Tag (si résultat est non nul ZF=0)
jc Tag (saut si retenue CF=1)
jnc Tag (saut si pas de retenue CF=0)
jo Tag (saut si débordement OF=1)
jno Tag (saut si pas de débordement OF=0)

22
17/11/2017

Instructions agissant sur RIP, exemples

Exemple 1
Init: movw $0, %cx # 0 -> cx
Boucle: addw $1, %cx # cx+1 -> cx
jnc Boucle # boucle tant que cx+1
# est valide (de 1 à 65535)
Exemple 2 (peut on remplacer: if else, while do, switch case, for?)
maximum: movq var_a, %rax # a -> rax (q: 64 bits)
movq var_b, %rbx # b -> rbx
subq %rax, %rbx # rbx-rax -> rbx
jc amax # CF=1 => b-a<0 => a>b
bmax: movq var_b, %rax # CF=0 => b-a>=0 =>
# a <= b, on copie
# b dans rax
amax: movq %rax, var_c # max(a,b) -> c

Structures de données

23
17/11/2017

Registres Pointeurs
• Un pointeur est une case mémoire qui contient l'adresse
d'une autre case mémoire.
• La modification du contenu d’une case mémoire peut se fait à
partir du pointeur qui a son adresse (il pointe sur elle)
Exemples de pointeurs:
• RIP est un exemple de registre pointeur qui point sur
l’instruction courante
• RSI (Re-extended source index) et RDI (Re-extended destination index)
sont deux pointeur indiquant la source et la destination (copie
de zone de mémoire)
• RSP (Re_extended Stack Pointer) et RBP (Re_extended Base Pointer)
deux pointeurs pour la gestion de la pile

Registres Pointeurs, Exemples

Exemple: mode d’adressage


movq $Tableau, %rsi # fait pointer %rsi sur
# le 1er élément du Tableau (adrs)
movw (%rsi), %ax # Copie l'élément
# courant du tableau dans ax
addw $1, %ax # Ajoute 1 à ax
movw %ax, (%rsi) # Remplace l'élément
# courant du tableau par ax
addl $1, %rsi # Ajoute 2 à rsi
#(pour passer à l'élément suivant)

Remarque: Un tableau en assembleur:


Tabb: .byte 6*7, 4, 8, -1 # sur un octet {42, 4, 8, -1}

24
17/11/2017

pointeur et adressage indirect

Exemple: mode d’adressage indirect


movq $Tableau, %rsi # fait pointer %rsi sur
# le 1er élément du Tableau (adrs)
movw (%rsi), %ax # Copie l'élément
# courant du tableau dans ax
addw $1, %ax # Ajoute 1 à ax
movw %ax, (%rsi) # Remplace l'élément
# courant du tableau (1er) par ax
movw 2(%rsi), %bx #copie directement le 2ème élément
#du tableau dans le registre bx
Remarque:
Le contenu du registre (rsi) reste inchangé (la même adresse)
Le déplacement le long de registre peut être + et -: -2(%rsi), 4(%rsi)

mode d’adressage indirect, Exemples


Exemple 2
rsi fiche fiche+1 fiche+2 fiche+3 fiche+4 fiche+5 fiche+6 fiche+7

$fiche Adresse du 1er élément de fihe : 0d490843500


(%rsi) 1(%rsi) 2(%rsi) 3(%rsi) 4(%rsi) 5(%rsi) 6(%rsi) 7(%rsi)
tel tel tel tel âge Année Année
naiss. naiss.

movq $fiche, %rsi # rsi pointe sur une fiche


movl (%rsi), %eax # copie le numéro de
# téléphone (4 octets) dans eax
movb 4(%rsi), %bl # copie l'âge de la personne
#(1 octet) dans bl
movw 5(%rsi), %cx # copie l'année de naissance dans cx

25
17/11/2017

Utilisation de la pile

L'utilisation de la est très utile, par exemple pour


simuler l'utilisation de « variables locales » ou
de paramètres de procédures

Fonctionnement de la pile
La pile est une zone spéciale réservée dans la mémoire pour stocker les données
d’un programme. Sa particularité réside dans la manière d’insertion et de
suppression des données de la pile.

Les données d’un programme sont


placées dans la mémoire (autre que la
pile) en commençant par des adresses
les plus basses vers les plus élevées.
La pile se comporte contrairement:
c’est une zone réservée à la fin de la
zone mémoire, les données sont
placées dans la pile en commençant
par l’adresse supérieure disponible et
ainsi de suite vers les adresses
inférieures.

26

Vous aimerez peut-être aussi