Cours gratuits » Cours informatique » Cours programmation » Cours Assembleur » Support de cours Assembleur ATMEGA32 : bases et opérations

Support de cours Assembleur ATMEGA32 : bases et opérations


Télécharger



★★★★★★★★★★3.5 étoiles sur 5 basé sur 1 votes.
Votez ce document:

 

 c Sovanna Tan

Novembre 2013

Plan

Introduction Les registres

Les instructions

Les structures de contrôle

Les tableaux

Les sous programmes

Les calculs flottants

Sources

 Introduction to 64 Bit Intel Assembly Language Programming for Linux, Ray Seyfarth, CreateSpace Independent Publishing Platform, 2nd edition , 2012.

La documentation Yasm, .

Le langage assembleur, Maˆ?trisez le code des processeurs de la famille X86, Olivier Cauet, Editions ENI, 2011.

Introduction à la programmation en assembleur 64 bits, Pierre Jourlin, , 2010.

Langage Assembleur PC (32 bits) , Paul A. Carter traduction

                      Sebastien Le Ray´              , 2005, .

Initiation à l’assembleur, Pierre Marchand, 2000, . .

Linux, Assembly Language Programming, Bob Neveln, Prentic

e Hall , 2000.

Le microprocesseur

 

Architecture simplifiée d’un processeur

Image provenant de : #cpu

Le langage assembleur

Langage de bas niveau

Chaque instruction se traduit directement en une instruction binaire pour le processeur.

Il existe différents dialects :

Yasm, the modular assembler : utilisé dans ce cours, en TD et en TP, issu de

Netwide asm (nasm) : utilisé les années précédentes

Gas : assembleur GNU utilisé avec gcc

Macro asm : assembleur Microsoft

Turbo asm : assembleur Borland

Premier programme en assembleur (1)

; fonctions externes pour l e s entrees / s o r t i e ; appel p r i n t f (”%s ” , prompt1 ) extern p r i n t f        mov rdi , stringFormat

extern          scanf                                                                                                              mov       rsi , prompt1

segment         .data        ;      memoire       globale                                                               mov rax ,0

                          ;      donnees      i n i t i a l i s e e s                                                c a l l     p r i n t f

prompt1 db ” Entrez un e n t i e r : ” ,0 ; appel scanf(”% ld ” , e n t i e r 1 ) prompt2 db ” Entrez un deuxieme e n t i e r : ” ,0 mov rdi , longIntFormat

formatSortie                db ”La somme       des    eux     e n t i e r s       : %ld ” ,10 ,0        mov     rsi , e n t i e r 1

stringFormat db longIntFormat db newLine db

segment       . b s s          ;

;

e n t i e r 1 resq 1 e n t i e r 2 resq 1 r e s u l t a t resq 1

segment       . t e x t        ;

global

”%s” ,0

”%ld ” ,0 10 ,0

memoire globale donnees non i t i a l i s e e s code du programme asm main

;

;

;

;

mov rax ,0

           c a l l      scanf

mov rbx , [ e n t i e r 1 ]

appel p r i n t f (”%s ” , prompt2 ) mov rdi , stringFormat mov rsi , prompt2 mov rax ,0 ; rax contient

parametres     de                    type                        double             dans p r i n t f c a l l                  p r i n t f

appel scanf(”% ld ” , e n t i e r 2 ) mov rdi , longIntFormat mov rsi , e n t i e r 2 mov rax ,0 ; rax contient

parametres         de     type       double           dans

l e nombre de l ’ appel de l e nombre de l ’ appel de

asm main :           ;       fonction        appelee      par     l e           programme C

;       sauvegarde       des     r e g i s t r e s     sur     la    p i l e

              push     rbp                                                                                   ;

;

scanf

 

                                                                                             c a l l      scanf

mov rcx , [ e n t i e r 2 ]

; c a l c u l de la somme et sauvegarde du r e s u l t a t add rbx , rcx mov [ r e s u l t a t ] , rbx


mov                 rax ,                 0 ret

Commandes de compilation

gcc                    -c -g -std=c99 -m64 driver.c yasm -g dwarf2 -f elf64 gcc                -m64 -g -std=c99 -o first driver.o first.o

Exécution du programme

./first

Entrez un entier : 7

Entrez un deuxieme entier : 34

La somme des eux entiers : 41


Introduction Les registres

Les instructions

Les structures de contrôle

Les tableaux

Les sous programmes

Les calculs flottants

Les principaux registres 64 bits

rax

registre général, accumulateur, contient la valeur de retour des fonctions

rbx

registre général

rcx

registre général, compteur de boucle

rdx

registre général, partie haute d’une valeur 128 bits

rsi

registre général, adresse source pour déplacement ou comparaison

rdi

registre général, adresse destination pour déplacement ou comparaison

rsp

registre général, pointeur de pile (stack pointer)

rbp

registre général, pointeur de base (base pointer)

r8

registre général

r9

registre général

.

.

.

 

r15

registre général

rip

compteur de programme (instruction pointer)


Accès à une partie du registre

Certaines parties des registres sont accessibles à partir des identifiants suivants :

rax, rbx, rcx, rdx,

rdi , rsi , rbp, rsp, r8, r9, ,r15

64 bits

eax, ebx, ecx, edx,

edi, esi , ebp, esp, r8d, r9d, ,r15d

32 bits

ax, bx, cx, dx, di,

si , bp, sp, r8w, r9w, ,r15w

16 bits (15:0)

ah, bh, ch, dh

 

8 bits high (15:8)

al , bl, cl , dl, dil ,                    sil , bpl, spl ,r8b, r9b, ,r15b

8 bits low (7:0)

Le registre RFLAGS

Le registre rflags contient des informations concernant le résultat de l’exécution d’une instruction.

Certains bits du registre appelés drapeaux ont une signification particulière.

Seuls les 32 bits de la partie eflags sont utilisés.

Drapeaux du registre RFLAGS

CF Carry Flag (bit 0)

retenue

PF Parity Flag (bit 2)

 

AF Auxiliary Carry Flag (bit 4)

 

ZF Zero Flag (bit 6)

vaut 1 lorsque le résultat est 0

SF Sign Flag (bit 7)

bit de signe du résultat

OF Overflow Flag (bit 11)

dépassement, le résultat contient trop de bits

DF Direction Flag (bit 10)

sens d’incrémentation de ESI et EDI

TF Task Flag (bit 8)

active la gestion de tâche en mode protégé

IF Interrupt Flag (bit 9)

interruption

IOPL I/O Privilege Level (bits 12 et 13)

 

NT Nested Task (bit 14)

 

RF Resume Flag (bit 16)

active le mode debug

VM Vitrual 8086 Mode (bit 17)

 

AC Alignement Check (bit 18)

 

VIF Virtual Interrupt Flag (bit 19)

 

VIP Virtual Interrupt Pending (bit 20)

 

ID Identification Flag (bit 21)

 

Introduction Les registres

Les instructions

Les structures de contrôle

Les tableaux

Les sous programmes

Les calculs flottants

Le langage assembleur

Langage de bas niveau

Chaque instruction se traduit directement en une instruction binaire pour le processeur.

Syntaxe : instruction source ou instruction destination source

Types de l’opérande source

registre mémoire immédiat, valeur codée dans l’instruction implicite, valeur qui n’apparaˆ?t pas dans l’instruction

Types de l’opérande destination registre mémoire

ATTENTION : Une instruction ne peut pas avoir deux opérandes de type mémoire.

Accès à la mémoire avec l’opérateur []

[cetteAdresse] représente la valeur stockée à l’adresse cetteAdresse.

[ceRegistre] représente la valeur stockée à l’adresse contenue dans le registre ceRegistre.

On peut associer une étiquette cetteEtiquette à une adresse mémoire et utiliser [cetteEtiquette].

Les directives de données

 Permettent de réserver de l’espace de mémoire dans les segments de données.

dx

dans le segment .data

données initialisées

resx

dans le segment .bss (Block Started by Symbol) données non initialisées

 La valeur du caractère x dépend de la taille des données.

b

1 octet (byte)

w

1 mot (word)

d

2 mots (double word)

q

4 mots (quadruple word)

t

10 octets

Les instructions de déplacement de données

mov dest,src mov taille dest,src

dest ? src

movzx dest,src

extension avec des 0 dans dest

movsx dest,src

extension avec le bit de signe dans dest

 Tailles possibles :

byte

1 octet

word

2 octets ou 1 mot

dword

2 mots

qword

4 mots

tword

10 octets

On utilise la taille pour lever l’ambigu¨?té dans les instructions quand c’est nécessaire. 1

lea dest,[op]

dest ? adresse de op (load effective address)

push op

décrémente rsp et empile op

pop op

dépile dans op et incrémente rsp

1. Ce n’est pas réservé à l’instruction mov.

La pile

De nombreux processeurs ont un support intégré pour une pile. Une pile est une liste Last-In First-Out (LIFO) : dernier entré, premier sorti.

push ajoute une donnée sur la pile de taille qword (64 bits). Cette donnée se trouve au sommet de la pile.

pop retire la donnée de taille qword qui se trouve au sommet de la pile.

Le registre rsp contient l’adresse de la donnée qui se trouve au sommet de la pile.

push décrémente rsp de 8. pop incrémente rsp de 8.


Roˆle la pile

Sauvegarde des registres

Passage des paramètres lors de l’appel de sous programme

Stockage de variables locales

Stockage des adresses de retour

Exemple :

push qword 1

;

1

est

stocke

en     0x0FFC ,           RSP = 0FFC

push qword 2

;

2

est

stocke

en     0x0FF4 ,           RSP = 0FF4

push qword 3

;

3

est

stocke

en     0x0FEC ,           RSP = 0FEC

pop rax         ; RAX = 3 , RSP = 0x0FF4 pop rbx      ; RBX = 2 , RSP = 0x0FFC pop rcx       ;               RCX = 1 , RSP = 0x1004

Les instructions arithmétiques

add op1,op2

op1 ? op1 + op2

sub op1,op2

op1 ? op1 ? op2

neg reg

reg ? ?reg

inc reg

reg ? reg + 1

dec reg

reg ? reg ? 1

imul op (signé ou mul non signé)

rdx:rax ? rax ×op

imul dest,op

dest ? dest × op

imul dest,op,immédiat

dest ? op×immédiat

idiv op (div non signé)

rax ? rdx:rax /op, rdx ? rdx:rax  mod op

Les opérations sur les bits

and op1,op2

op1 ? op1 & op2

or op1,op2

op1 ? op1 | op2

xor op1,op2

op1 ? op1 ˆ op2

not reg

reg ? ˜reg

shl reg,immédiat

reg ? reg

<< immédiat

shr reg,immédiat

reg ? reg

>> immédiat

sal reg,immédiat

reg ? reg

<< immédiat

sar reg,immédiat

reg ? reg

>> immédiat signé

rol reg,immédiat

reg ? reg

decalageCirculaireGaucheDe imm

ror reg,immédiat

reg ? reg

decalageCirculaireDroiteDe imm

rcl reg,immédiat

reg : CF ? reg : CF decalageCircGauchede imm

rcr reg,immédiat

reg : CF ? reg : CF decalageCircDroitede imm


Les instructions de comparaison et de branchement

cmp op1,op2

calcul de op1 ? op2 et de ZF,CF et OF

jmp op

branchement inconditionnel à l’adresse op

jz op

branchement à l’adresse op si ZF=1

jnz op

branchement à l’adresse op si ZF=0

jo op

branchement à l’adresse op si OF=1

jno op

branchement à l’adresse op si OF=0

js op

branchement à l’adresse op si SF=1

jns op

branchement à l’adresse op si SF=0

jc op

branchement à l’adresse op si CF=1

jnc op

branchement à l’adresse op si CF=0

jp op

branchement à l’adresse op si PF=1

jnp op

branchement à l’adresse op si PF=0

Les instructions de branchement après cmp op1,op2

Signées :

je op

branchement à l’adresse op si op1 = op2

jne op

branchement à l’adresse op si op1 6= op2

jl op (jnge)

branchement à l’adresse op si op1 < op2

jle op (jng)

branchement à l’adresse op si op1 ? op2

jg op (jnle)

branchement à l’adresse op si op1 > op2

jge op (jnl)

branchement à l’adresse op si op1 ? op2

Non signées :

je op

branchement à l’adresse op si op1 = op2

jne op

branchement à l’adresse op si op1 6= op2

jb op (jnae)

branchement à l’adresse op si op1 < op2

jbe op (jna)

branchement à l’adresse op si op1 ? op2

ja op (jnbe)

branchement à l’adresse op si op1 > op2

jae op (jnb)

branchement à l’adresse op si op1 ? op2

Exemple de branchement

i f : else :

cmp r12 , r13

jng        else

mov qword rdi , format mov qword rsi , r12 mov qword rax , 0

call        p r i n t f

jmp endif

mov qword rdi , format mov qword rsi , r13 mov qword rax , 0

call        p r i n t f

endif :

i f (a>b){

p r i n t f (”%d” ,a ) ;

} else { p r i n t f (”%d” ,b ) ;

}


Les boucles

Les instructions suivantes sont déconseillées car elles ne permettent qu’un branchement à une distance inférieure à 127 octets.

loop op

décrémente rcx et saut à op si rcx6= 0

loope op (loopz)

rcx?? et saut à op si rcx6= 0 et ZF=1

loopne op (loopnz)

rcx?? et saut à op si rcx6= 0 et ZF=0

Exemple :

for ( int a=10;a>0;a??){ p r i n t f (”%d” ,a)

}

for1 :

mov rcx ,10

push      rcx

mov qword rdi , format mov qword rsi , rcx mov qword rax , 0

call        p r i n t f

pop rcx

loop        for1

Introduction Les registres

Les instructions

Les structures de contrôle

Les tableaux

Les sous programmes

Les calculs flottants

if

i f (a>b){                                                                if1 :                cmp rax , rbx

                                                                                                        jng      else1

       . . .                                                                                          . . .

}        jmp        endif1 else {       else1 :

       . . .                                                                                          . . .

      }                                                                         endif1 :

i f (( a > b) && ( c <= d )) { if2 : cmp rax , rbx jng endif2

cmp rcx , rdx jnle  endif2

       . . .                                                                                          . . .

      }                                                                         endif2 :


switch

switch ( i ) { case 1:

. . .

break ;

             case     2:

. . .

break ; default :

. . .

switcha :

cmp rcx ,1 jne casea2

. . .

jmp endswitcha

casea2 : defaulta :

cmp rcx ,2 jne defaulta

. . .

jmp endswitcha

} . . . . . . endswitcha :

. . .


while, do while

while (a>0){

. . .

a??;

}

do {

. . .

a??;

}while (a >0);

while1 : cmp rax ,0

                        j l e        endwhile1

. . .

dec rax

jmp while1

endwhilei1 :            . . .

do2 :

. . .

dec rax ;

cmp rax ,0

                        jg     do2

for

for ( int

. . .

} . . .

i =1; i <10; i ++){

for1 : next1 : test1 :

mov rcx ,1 jmp test1

. . .

inc       rcx

cmp rcx ,10 j l next1

. . .


Introduction Les registres

Les instructions

Les structures de contrôle

Les tableaux

Les sous programmes

Les calculs flottants

Les tableaux

Bloc continu de données en mémoire

Tous les éléments sont de même type et de même taille.

L’adresse de chaque élément du tableau se calcule à partir de l’adresse du premier élément du tableau; le nombre d’octets de chaque élément; l’indice de l’élément.

L’indice du premier élément du tableau est 0.

Tableau à deux dimensions : tableau de tableaux à une dimension.

Se généralise pour les dimensions supérieures.

 Chaˆ?ne de caractères : tableau d’octets dont le dernier élément est 0.

Exemples de définition de tableau

segment .data

          ;    d e f i n i t   un     tableau      de   10     doubles      mots    i n i t i a l i s e s

          ;    a     1 ,2 , .. ,10

          a1                 dd 1 ,     2 ,    3 ,    4 ,   5 ,    6 ,    7 ,   8 ,    9 ,   10

          ;    d e f i n i t   un     tableau      de   10      quadruples       mots    i n i t i a l i s e s    a

          a2                 dq 0 ,     0 ,    0 ,    0 ,   0 ,    0 ,    0 ,   0 ,    0 ,   0

          ;    idem    mais    en   u t i l i s a n t     times

          a3                  times       10 dq 0

;    d e f i n i t      un

tableau

d ’ octets               avec

200    0

puis         100    1

a4                    times

200 db

0

       

times

segment . b ss

100 db

1

       

;    d e f i n i t      un

tableau

de

10

doubles

mots

non    i n i t i a l i s e s

a5                      resd

10

     

;    d e f i n i t      un

tableau

de

100

mots       non    i n i t i a l i s e s

          a6                 resw    100

Exemple d’accès aux éléments d’un tableau

array1

db 50 ,        40 ,    30 ,     200 ,     100     ;      tableau           d ’ octets

array2

dw 5 ,       4 ,    3 ,    2 ,    1    ;      tableau       de     mots

mov al , [ array1 ] ; al=array1 [ 0 ] mov al , [ array1 +1] ; al=array1 [ 1 ] mov [ array1 + 3] , al ; array1 [3]= al mov ax , [ array2 ] ; ax=array2 [ 0 ] mov ax , [ array2 + 2] ; ax=array2 [ 1 ] mov [ array2 + 6] , ax ; array2 [3]= ax mov ax , [ array2 +1] ; ax=??

Calcul de la somme des éléments du tableau array1

mov rbx , array1

;

rbx = adresse                de      array1

mov rdx ,0

;

dx           contiendra        la     somme

mov rcx ,5 next1 :

;

i n i t i a l i s a t i o n        compteur          boucle

add dl , [ rbx ]

;

dl += ?ebx

                jnc       suite1

;

s i      pas     de      retenue       goto            suite1

inc dh suite1 :

;

incremente          dh    quand       retenue

inc rbx dec rcx

cmp rcx ,0 jg next1

;

bx++

Adressage indirect

L’adressage indirect facilite l’accès aux éléments d’un tableau ou de la pile.

            [ deplacement+r e g i s t r e        b a s e+facteur ? r e g i s t r e     i n d e x ]

registre base et registre index sont des registres généraux

facteur vaut 1, 2, 4 ou 8 (omis lorsqu’il vaut 1). deplacement est une étiquette.

Exemple : tri par sélection (1)

extern           p r i n t f

segment          .data longIntFormat stringFormat newLine

db ”%ld ” ,0 db ”%s” ,0 db 10 ,0

                       for1 :             mov rcx ,0

jmp test1 ; rbx contient a [ rcx ] next1 : mov rbx , [ a+8?rcx ]

mov rdx , rcx

a dq 7 , 5 , 2 , 18 , 14 , 8 push rcx segment . b s s                  inc rdx

;     t r i     par    s e l e c t i o n    du      tableau      b                                       i f 1 :            cmp         rbx , [ a+8?rdx ]

;       elements      de    a      numerotes      de      0 a n?1                                                    jng       endif1


;      pour    i    de       0 a n?2

;             min <? i

;           pour     j    de          i + 1 a n?1

; s i a [ j ] < a [ min ] min ; s i min != i echanger

segment       . t e x t global     asm main

asm main :

; sauvegarde pointeur p i l e push rbp mov rbp , rsp push r12

; valeur min dans rbx mov rbx , [ a+8?rdx ]

                                 ;       sauvegarde       de    i n d i c e    min     sur     p i l e

<? j                  push rdx a [ i ] et a [ min ] endif1 : inc rdx test2 : cmp rdx ,6 j l i f 1

; min dans rbx , echange mov rax , [ a+8?rcx ] mov [ a+8?rcx ] , rbx pop rdx mov [ a+8?rdx ] , rax

                                               inc     rcx

test1 : cmp rcx ,5 j l next1


Exemple : tri par sélection (2)

Exécution du programme

; a f f i c h a g e    du      tableau

./trisel1

mov r12 ,0

2 5 7 8 14 18

              jmp     test3

next3 :

mov rdi , longIntFormat mov rsi , [ a+8?r12 ] mov rax ,0

c a l l p r i n t f inc r12

test3 :

cmp r12 ,6

            j l      next3

mov rdi , stringFormat mov rsi , newLine mov rax , 0

            c a l l                 p r i n t f

; r e s t a u r a t i o n pointeur p i l e pop r12

mov rsp , rbp pop rbp

mov rax ,0 ret


Introduction Les registres

Les instructions

Les structures de contrôle

Les tableaux

Les sous programmes

Les calculs flottants

Appel de sous programme

Sous programme

Partie du code écrite une seule fois que l’on peut exécuter à partir de différents endroits du programme.

Implémentation des procédures et des fonctions des langages de haut niveau.

A la fin de l’exécution d’un sous programme, l’exécution doit se poursuivre avec l’instruction qui suit l’appel.

Impossible à implémenter avec une étiquette.

Il faut mémoriser l’adresse de retour et faire un saut à cette adresse en utilisant l’adressage indirect. On dispose des instructions suivantes :

call op

saut inconditionnel à op

et empile l’adresse de l’instruction suivante

ret

dépile une adresse et saute à cette adresse

Attention à la gestion de la pile!

La valeur de retour des fonctions

Elles sont passées par des registres :

rax pour un pointeur ou un type entier de taille inférieure ou égale à 64 bits (Les valeurs sont étendues sur 64 bits.); rdx:rax pour une valeur 128 bits; xmm0 pour une valeur flottante ou xmm1:xmm0 si besoin.


Exemple : calcul de

extern p r i n t f segment .data

n2 ? 1

formatSortie1 db ”6ˆ2?1vaut formatSortie2 db ”8ˆ2?1vaut segment . b s s

segment       . t e x t global     asm main

asm main :

: %ld ” ,10 ,0

: %ld ” ,10 ,0

; sauvegarde des r e g i s t r e s sur push rbp

la       p i l e

; 1 er appel de la fonction mov rdi ,6 c a l l fonc1

; appel p r i n t f mov rdi , formatSortie1 mov rsi , rax mov rax ,0

              c a l l     p r i n t f

; 2eme appel de la fonction mov rdi ,8 c a l l fonc1

; appel p r i n t f mov rdi , formatSortie2 mov rsi , rax mov rax ,0

              c a l l    p r i n t f

; r e s t a u r a t i o n des r e g i s t r e s pop rbp

; envoi de 0 au programme C mov rax , 0 ret

; code fonc1 :

de

la

fonction

push rbp mov rbp , rsp imul rdi , r d i sub rdi ,1 mov rax , r d i mov rsp , rbp pop rbp ret


Code réentrant

Sous programme réentrant

Un sous programme réentrant peut être utilisé simultanément par plusieurs tâches. Une seule copie du code en mémoire peut être utilisée par plusieurs utilisateurs en même temps. Pour cela, le sous programme réentrant ne doit pas :

modifier son code; modifier les données globales comme celles des segments .data et .bss. Toutes les variables locales doivent être stockées sur la pile.

Calcul récursif

Sous programme récursif

Un sous programme récursif est un sous programme qui s’appelle lui même :

directement; ou indirectement par l’intermédiaire d’autres appels de fonctions.

Un sous programme récursif doit avoir une condition de terminaison pour que le programme s’arrête, sinon il engendre une erreur à l’exécution lorsque les ressources sont épuisées.

Un sous programme réentrant peut s’appeler de manière récursive.

Les variables locales

 On alloue l’espace requis par les variables locales en diminuant rsp. La taille des blocs doit être un multiple de 16 pour Windows et Linux.

On peut alors mettre les valeurs des variables locales dans [rsp], [rsp+8],

A la fin du sous programme, on libère l’espace mémoire correspondant avec mov rsp,rbp

Les instructions enter et leave

 Simplifient l’écriture des sous programmes.

enter

. . .             ; leave ret

TAILLE VAR LOC ,0

push rbp

mov rbp , rsp

sub rsp , TAILLE VAR LOC

. . .     ;      code du ss         prog

mov rsp , rbp

pop rbp ret

code du ss

prog

       

TAILLE VAR LOC doit être un multiple de 16. Le pointeur rsp doit contenir la valeur 0 en hexadécimal pour le chiffre des unités.

Les systèmes d’exploitation Windows et Linux demandent le maintien du pointeur de pile aligné sur un bloc de 16 octets. Sa valeur en hexadécimal doit contenir 0 pour le chiffre des unités. Un appel de fonction avec la valeur 8 en hexadécimal pour le chiffre des unités de rsp conduit à une segmentation fault.


La pile des appels de fonctions (stack frame)

Comme chaque call empile, l’adresse de l’instruction à exécuter après le retour de l’appel, le fait de commencer un appel de fonction par

enter TAILLE VAR LOC ,0

ou

push rbp

mov rbp , rsp

sub rsp , TAILLE VAR LOC

et de le terminer par leave permet au débogueur de remonter la pile des appels de fonctions.

Exemple de sous programme récursif : calcul de n!

extern        p r i n t f                                                                                         fact :

segment .data ; une v a r i a b l e l o c a l e e n t i e r e formatSortie1 db ” 5! vaut : %ld ” ,10 ,0 enter 16 ,0

segment . b s s; sauvegarde du parametre n segment . t e x tmov [ rsp ] , r d i global asm main ; cas n==1

asm main :

; sauvegarde des r e g i s t r e s push rbp

; appel de la fonction pour mov rdi ,5

sur n=5

la

p i l e

;

          cmp      rdi ,1

je      term cond cas <>1                  c a l c u l                        de dec                        r d i

           c a l l      fact

fact (n?1)

              c a l l      fact                                                                              ;           fact (n)= fact (n?1)?n

; appel p r i n t f                      imul rax , [ rsp ] mov rdi , formatSortie1 jmp end fact mov rsi , rax             termcond : mov rax ,0            ; fact (1)=1 c a l l p r i n t fmov rax ,1

;    r e s t a u r a t i o n    des     r e g i s t r e s                                                     endfact :

              pop    rbp                                                                                                        leave

mov                     rax ,                 0                      ret ret

Conventions d’appel d’un sous programme

 Lors de l’appel d’un sous programme, le code appelant et le sous programme doivent se coordonner pour le passage des paramètres.

Ce processus est normalisé dans les langages de haut niveau. Ce sont les conventions d’appel.

Au niveau de l’assembleur, il n’y a pas de norme. Les conventions diffèrent d’un compilateur à l’autre.

Pour interfacer, l’assembleur avec un langage de haut niveau l’assembleur doit suivre les conventions d’appel du langage de haut niveau.

Contenu de la convention d’appel

Ou` le code appelant place-t-il les paramètres : sur la pile ou dans des registres?

Quand les paramètres sont placés sur la pile, dans quel ordre y sont-ils placés : du premier au dernier ou du dernier au premier?

Quand les paramètres sont placés sur la pile, qui doit nettoyer la pile suite à l’appel : le code appelant ou le code du sous programme?

 Quels sont les registres préservés (callee-save) que le sous programme doit sauver avant d’utiliser et restaurer à la fin et les registres de travail (caller-save) dont l’appelant a sauvé le contenu et qui peuvent être utilisés par le sous programme à volonté?

 Ou` se trouve la valeur de retour d’une fonction?

Le passage des paramètres

Le passage des paramètres peut se faire par les registres comme dans les fonctions fonc1 et fact.

S’il y a trop de paramètres, il faut en passer certains par la pile.

On empile les paramètres avant le call.

Si le sous programme doit modifier le paramètre, il faut passer l’adresse de la donnée à modifier.

Si la taille du paramètre est inférieure à celle d’un qword, il faut l’étendre avant de l’empiler.

Les paramètres ne sont pas dépilés par le sous programme mais on y accède depuis la pile.

L’adresse de retour empilée par call doit être dépilée en premier. Les paramètres peuvent être utilisés plusieurs fois dans le sous programme.

Les conventions d’appel du C (cdecl)

Les paramètres sont empilés dans l’ordre inverse de celui dans lequel ils sont écrits dans la fonction C.

Utilisation du registre rbp pour accéder aux paramètres passés par la pile (écriture simplifiée avec enter et leave).

Le sous programme doit empiler rbp avec push rbp puis copier rsp dans rbp avec mov rbp,rsp.

On accède aux paramètres en utilisant rbp. Les paramètres sont

[rbp+16], [rbp+24]

Cela permet de continuer à utiliser la pile dans le sous programme pour stocker les variables locales afin d’écrire du code réentrant.

On alloue l’espace requis par les variables locales en diminuant rsp.

A la fin du sous programme, on libère l’espace mémoire correspondant avec mov rsp,rbp

A la fin de l’appel, le sous programme doit restaurer la valeur de rbp avec pop rbp .

Le code appelant doit retirer les paramètres de la pile.


Différences entre Linux et Windows

Les six premiers paramètres entiers sont passés dans rdi, rsi , rdx, rcx, r8 et r9 dans cet ordre. Les autres sont passés par la pile.

Ces registres, ainsi que rax, r10 et r11 sont détruits par les appels de fonctions.

Les registres callee-save sont rbx, r12, , r15.

Sovanna Tan

Assembleur intel

Les paramètres flottants sont passés dans xmm0, xmm1, , xmm7.

Les quatre premiers paramètres entiers sont passés dans rcx, rdx, r8 et r9 dans cet ordre. Les autres sont passés par la pile. Ces registres, ainsi que rax, r10 et r11 sont détruits par les appels de fonctions.

La valeur de retour entière est contenue seulement dans rax. Les paramètres flottants sont passés dans xmm0, xmm1, xmm2 et xmm3.

La valeur de retour flottante est contenue seulement dans xmm0.

D’autres conventions

sdtcall :

Le sous programme doit retirer les paramètres de la pile. Cela empêche l’écriture de fonctions à nombre variable d’arguments comme printf ou scanf.

Utilisée dans l’API Microsoft.

Avec gcc, on peut préciser cdecl ou sdtcall dans le code C.

Pascal :

Les paramètres sont empilés dans l’ordre ou` ils apparaissent dans la fonction, de gauche à droite.

Le sous programme doit retirer les paramètres de la pile.

Utilisée dans Delphi de Borland.

Fonction qui affiche un tableau d’entier


extern p r i n t f segment .data

 

longIntFormat

db            ”%ld ” ,0

stringFormat

db ”%s” ,0

newLine

db     10 ,0

a dq 7 , 5 , 2 , 18 , 14 , 8 segment . b s s segment . t e x t global asm main

asm main :

              push     rbp

; a f f i c h e l e s 6 elements du tableau mov rdi , a mov rsi ,6

              c a l l    a f f i c h a g e

; a f f i c h e 3 elements a p a r t i r du 2eme mov rdi , a add rdi ,16 mov rsi ,3 c a l l a f f i c h a g e

pop rbp mov rax ,0 ret

; a f f i c h a g e du tableau a f f i c h a g e : push rbp mov rbp , rsp

 

mov rbx , r d i mov r13 , r s i mov r12 ,0 jmp test3

next3 :

mov rdi , longIntFormat mov rsi , [ rbx+8?r12 ] mov rax ,0

c a l l p r i n t f inc r12

test3 :

cmp r12 , r13

j l         next3

mov rdi , stringFormat mov rsi , newLine mov rax , 0 c a l l p r i n t f

leave

mov rax ,             0 ret

. / afftab

7 5 2        18    14    8

2    18    14

extern p r i n t f segment .data

   

longIntFormat

db

”%ld ” ,0

stringFormat

db

”%s” ,0

newLine

db

10 ,0

Tri par sélection avec fonctions (1)

a dq 7 , 5 , 2 , 18 , 14 , 8 b dq 27 , 35 , 12 , 25 , 19 , 12 , 34 segment . b s s

;     t r i     par    s e l e c t i o n    du      tableau      t

;       elements      de   a      numerotes      de      0 a n?1

;      pour     i    de       0 a n?2

;             min <? i

;           pour     j    de         i + 1 a n?1

; s i t [ j ] < t [ min ] min <? j ; s i min != i echanger t [ i ] et t [ min ]

segment       . t e x t global     asm main

asm main :

              push     rbp

;      appel     de     la       fonction       t r i s e l

;     l e      premier        parametre ,         adresse      du       tableau ,

;     et     l e      deuxieme        parametre ,        t a i l l e     du        tableau

;      sont       passes      dans     l e s    r e g i s t r e s     r d i     et         r si ,

;     l e       troisieme          parametre ,           nombre d ’ elements

;    a     t r i e r ,     est      passe      par     la    p i l e

; t r i de a mov rdi , a mov rsi ,6 push 6 c a l l t r i s e l

              add     rsp ,8

; a f f i c h a g e du tableau mov rdi , a mov rsi ,6

              c a l l     a f f i c h a g e

: t r i des 5 premiers elements de b mov rdi , b mov rsi ,7 push 5 c a l l t r i s e l

              add     rsp ,8

; a f f i c h a g e du tableau mov rdi , b mov rsi ,7 c a l l a f f i c h a g e

pop rbp mov rax ,0 ret


Tri par sélection avec fonctions (2)


; fonction de t r i t r i s e l : enter 0 ,0 mov r12 , r d i mov r14 , r s i mov r13 , [ rbp+16] dec r13

for1 : mov rcx ,0 jmp test1 ; rbx contient t [ rcx ] next1 :

;       sauvegarde       des   r e g i s t r e s

; et a f f i c h a g e du tableau push rcx push rdx mov rdi , r12 mov rsi , r14 c a l l a f f i c h a g e pop rdx pop rcx

mov rbx , [ r12+8?rcx ] mov rdx , rcx push rcx inc rdx

i f 1 : cmp rbx , [ r12+8?rdx ] jng endif1

; valeur min dans rbx mov rbx , [ r12+8?rdx ]

; sauvegarde de i n d i c e min sur p i l e push rdx

endif1 : inc rdx test2 : cmp rdx , [ rbp+16] j l i f 1

; min dans rbx , echange mov rax , [ r12+8?rcx ] mov [ r12+8?rcx ] , rbx pop rdx mov [ r12+8?rdx ] , rax

              inc     rcx

test1 : cmp rcx , r13 j l next1

leave ret


Tri par sélection avec fonctions (3)

./trisel2

7 5 2 18 14 8

2 5 7 18 14 8

2 5 7 18 14 8

2 5 7 18 14 8

2 5 7 8 14 18

2 5 7 8 14 18

27 35 12 25 19 12 34

12 35 27 25 19 12 34

12 19 27 25 35 12 34

12 19 25 27 35 12 34

12 19 25 27 35 12 34

Introduction Les registres

Les instructions

Les structures de contrôle

Les tableaux

Les sous programmes

Les calculs flottants


L’unité de calcul flottant (FPU : Floating Point Unit)

Au début, elle était un circuit séparé, le coprocesseur mathématique.

Puis, elle a été intégrée au microprocesseur, mais se programmait toujours de fac¸on distincte.

Avec les architectures 64 bits, apparaˆ?t un nouveau jeu d’instructions SSE (Streaming SIMD (Single Instruction Multiple Data) Extensions) pour des registres de taille 128 ou 256 bits selon les processeurs.

Les types de nombres flottants

Simple précision IEEE 754-2008 : 1 bit signe, 8 bits exposant, 23 bits mantisse

Double précision IEEE 754-2008 : 1 bit signe, 11 bits exposant, 52 bits mantisse

Precision étendue intel 80 bits : 1 bit signe, 15 bits exposant,

64 bits mantisse

Ce format est différent des formats IEEE 754-2008.

Dans le processeur Intel 32 bits, tous les calculs étaient effectués en précision étendue puis convertis en simple ou double précision IEEE 754-2008.

Quadruple précision IEEE 754-2008 : 1 bit signe, 15 bits exposant, 112 bits mantisse

256 bits (extrapolation de IEEE 754-2008) : 1 bit signe, 19 bits exposant, 236 bits mantisse

Les registres

16 registres généraux xmm0, xmm1, et xmm15.

Ces registres peuvent être utilisés avec des instructions pour une seule valeur ou pour un vecteur de valeurs.

Ce vecteur comporte alors soit 4 floats soit 2 doubles.

 Les processeurs de la série i-core ont 16 registres 256 bits ymm0, ymm1, et ymm15. Les registres xmm0, xmm1, et xmm15 correspondent aux premiers 128 bits des registres ymm0, ymm1, et ymm15. Ces derniers peuvent être vu comme des vecteurs de 8 floats ou 4 doubles.

Les instructions de déplacement de données

movsd dest,src

déplacement d’un flottant double

movss dest,src

déplacement d’un flottant simple (float)

 Déplacement de paquets (plusieurs valeurs simultanément)

movapd dest,src

déplacement de 2 doubles alignés

movaps dest,src

déplacement de 4 floats alignés

movdqa dest,src

déplacement d’un double qword aligné

movupd dest,src

déplacement de 2 doubles non alignés

movups dest,src

déplacement de 4 floats non alignés

movdqu dest,src

déplacement d’un double qword non aligné

 Les noms des instructions pour les registres 256 bits commencent par v, vmovapd, vmovaps,

Calculs flottants

addsd dest,src

addition de 2 doubles

addss dest,src

addition de 2 floats

addpd dest,src

2 doubles + 2 doubles

addps dest,src

4 floats + 4 floats

subsd dest,src

soustraction de 2 doubles

subss dest,src

soustraction de 2 floats

subpd dest,src

2 doubles - 2 doubles

subps dest,src

4 floats - 4 floats

mulsd dest,src

multiplication de 2 doubles

mulss dest,src

multiplication de 2 floats

mulpd dest,src

2 doubles * 2 doubles

mulps dest,src

4 floats * 4 floats

divsd dest,src

division de 2 doubles

divss dest,src

division de 2 floats

divpd dest,src

2 doubles / 2 doubles

divps dest,src

4 floats / 4 floats

 dest doit être un registre flottant.


Les instructions de conversion

cvtss2sd dest,src

convertit un float en double

cvtps2pd dest,src

convertit un paquet de 2 floats en un paquet de 2 doubles

cvtsd2ss dest,src

convertit un double en float

cvtpd2ps dest,src

convertit un paquet de 2 doubles en un paquet de 2 floats

cvtss2si dest,src

convertit un float en dword ou qword

cvtsd2si dest,src

convertit un double en dword ou qword

cvtsi2ss dest,src

convertit un entier en float

cvtsi2sd dest,src

convertit un entier en double

 Lorsque l’opérande source est dans la mémoire, il faut préciser la taille de la donnée à lire.

Les instructions de comparaison

comisd op1,op2

comparaison ordonnée de deux doubles

comiss op1,op2

comparaison ordonnée de deux floats

ucomisd op1,op2

comparaison non ordonnée de deux doubles

ucomiss op1,op2

comparaison non ordonnée de deux floats

op1 doit être un registre, ,op2 peut être un registre ou une valeur en mémoire.

Les instructions mettent à jour les drapeaux ZF, PF et CF.

Les comparaisons non ordonnées lèvent une exception si l’un des opérandes vaut SNaN (Signaling Not a Number i.e. que des 1 dans l’exposant et mantisse de la forme 0x) et les comparaisons ordonnées lèvent une exception si l’un des deux opérandes vaut

SNaN ou QNaN (Quiet Not a Number i.e. que des 1 dans l’exposant et mantisse de la forme 1x).

Les branchements conditionnels pour les flottants

 Après une instruction de comparaison de flottants (comisd, comiss, ucomisd ou ucomiss) entre op1 et op2 :

jb op

branchement à op si op1

< op2

CF=1

jbe op

branchement à op si op1

? op2

CF=1 ou ZF=1

ja op

branchement à op si op1

> op2

CF=1

jae op

branchement à op si op1

? op2

CF=1 ou ZF=1

Arrondis

roundsd dest,src,mode

arrondi src de type double dans dest

roundss dest,src,mode

arrondi src de type float dans dest

roundpd dest,src,mode

arrondi des 2 doubles de src dans dest

roundps dest,src,mode

arrondis des 4 floats de src dans dest

dest doit être un registre flottant. mode est un opérande immédiat :

0

arrondi à la valeur entière paire la plus proche

1

arrondi à la valeur entière inférieure

2

arrondi à la valeur supérieure

3

arrondi à la valeur absolue inférieure

(à la valeur entière la plus proche de 0)

Instructions diverses

minsd dest,src

minimun de 2 doubles (src et dest) dans dest

minss dest,src

minimun de 2 floats (src et dest) dans dest

minpd dest,src

2 calculs de minimun de 2 doubles dans dest

minps dest,src

4 calculs de minimun de 2 floats dans dest

maxsd dest,src

maximun de 2 doubles (src et dest) dans dest

maxss dest,src

maximun de 2 floats (src et dest) dans dest

maxpd dest,src

2 calculs de maximun de 2 doubles dans dest

maxps dest,src

4 calculs de maximun de 2 floats dans dest

sqrtsd dest,src

racine carrée de src de type double dans dest

sqrtss dest,src

racine carrée de src de type float dans dest

sqrtpd dest,src

2 racines carrées de src(2 doubles) dans dest

sqrtps dest,src

4 racines carrées de src(4 floats) dans dest

 dest doit être un registre flottant.


Exemple : calcul de la valeur d’un polynoˆme (1)

extern printf , scanf lea rdi , [ c oeff ] segment .data            movsd xmm0, [ y ]

coeff dq 1.0 , 2.0 , 3.0 , 4 .0 mov esi , 3 x dq 2 .0                  c a l l horner

promptDouble db ”%l f ” ,0 mov rdi , prompt2Doubleln prompt1Doubleln db ”4x3+3x2+2x+1(2) = %l f ” ,10 ,0 movsd xmm1,xmm0

prompt2Doubleln db ”4x3+3x2+2x+1(% l f ) = %l f ” ,10 ,0 movsd xmm0, [ y ] promptEntrer db ” Entrez x : ” ,0 mov rax ,2

               segment     . b s s                                                                                          c a l l     p r i n t f

y resq 1        xor eax , eax segment . t e x t   leave global asm main , horner ret

asm main : ; e x t r a i t du l i v r e de Ray Seyfarth push rbp horner : movsd xmm1, xmm0 mov rbp , rsp ; use xmm1 as x

              lea                rdi ,       [ coe ff ]                                                                       movsd         xmm0,            [ r d i+r s i ?8]

movsd xmm0, [ x ] ; accumulator for b k mov esi , 3                 cmp esi , 0 c a l l horner ; i s the degree 0?


jz

done

more :

sub                 esi ,     1

mulsd

? x

xmm0, xmm1

addsd

p k

xmm0,          [ r d i+r s i ?8]

jnz ret

more

mov rdi , prompt1Doubleln mov rax ,1

              c a l l    p r i n t f

             mov         rdi , promptEntrer                                                      ;     b k

mov rax ,0

              c a l l     p r i n t f                                                                        ;    add

mov rdi , promptDouble mov rsi , y                    done :

mov rax ,0 c a l l scanf

Exemple : calcul de la valeur d’un polynoˆme (2)

. / horner

4x3+3x2+2x+1 (2) = 49 .000000

           Entrez      x    :    3

4x3+3x2+2x+1 (3 .000000 ) = 142 .000000

Exemple : calcul de la somme de deux vecteurs (1)


extern p r i n t f segment .data

a dq 1.0 , 2.0 , 3.0 b dq 2.0 , 0.5 , 4.0 floatFormat db ”%l f ” ,0 promptRes db ”a?b=” ,0 promptln db 10 ,0 segment . b s s

c                    resq     8

segment . t e x t global asm main ,

asm main :

push    rbp mov           rbp ,                 rsp

,

,

4.0 ,

0.2 ,

5.0 ,

3.0 ,

6.0 ,

1.5 ,

7.0 ,

0.5 ,

8 .0

0 .4

mov mov c a l l mov

rdi , b rsi , 8 a f f i c h a g e rdi , c

           

mov

      rsi ,     8

           

c a l l

a f f i c h a g e

           

mov leave ret

rax ,0

mov rcx ,0 mov rdx ,8 jmp test1 horner            a f f i c h a g e :

enter               0 ,0 push          r12 push          r13 push          r14 push          rbx


next1 :

movapd           xmm0, [ a+8?rcx ] movapd           xmm1, [ b+8?rcx ] addpd              xmm1,xmm0 movapd           [ c+8?rcx ] ,xmm1

 

test1 :

add      rcx ,2

cmp rcx , rdx

j l       next1

next3 :

mov rdi , a mov rsi , 8             test3 : c a l l a f f i c h a g e

mov rbx , r d i mov r13 , r s i mov r12 ,0 jmp test3 mov rdi , floatFormat movsd xmm0, [ rbx+8?r12 ] mov rax ,1 c a l l p r i n t f inc r12 cmp r12 , r13 j l next3


Exemple : calcul de la somme de deux vecteurs (2)

              mov         rdi ,

promptln

mov rax ,

0

c a l l

pop rbx pop r14 pop r13 pop r12

p r i n t f

mov rax , leave ret

. / addvect

0

1.000000 2.000000 3.000000 4.000000 5.000000 6.000000 7.000000 8.000000 2.000000 0.500000 4.000000 0.200000 3.000000 1.500000 0.500000 0.400000

3.000000          2.500000        7.000000        4.200000        8.000000        7.500000        7.500000          8.400000

 


[1] . Ne pas oublier de mettre 0 dans rdx avant d’appeler idiv.

. alignés sur 1 bloc de 16 octets


50