Cas de l'instruction enter
Page 1 sur 1
Cas de l'instruction enter
Précédemment, nous avons vu le passage d'un paramètre par push et sa récupération par l'instruction mov rax,[rsp+8]. Mais ce n'est pas la meilleure façon de procéder car l'adresse de la pile peut évoluer et donc l'adresse du paramètre aussi. Normalement il faut utiliser l'instruction enter qui va fixer la pile de base rbp en début d'une sous procédure.
L'instruction enter contient une instruction push rsp qui va déphaser la pile de 8 octets et donc après cette instruction il faudra réaligner la pile (ne pas oublier les 8 octets du call et les 8 octets du push du parametre).
Mais attention, l'instruction enter sert dans son premier paramètre à réserver de la place pour stocker des données locales à la procédure (bien utile en cas d'appel récursif de la procédure). Si nous réservons 8 octets par exemple et bien nous déphasons de nouveau la pile de 8 octets et donc nous devrons gérer son impact.
Globalement si nous avons un nombre de paramètres plus le nombre de réservation de 8 octets de variable locales impair , nous devons réaligner la pile . Si ce nombre est pair, il ne faut pas la réaligner.
Voyons 2 exemples :
Passage de 2 paramètres et réservation de place par enter :
Passage de 2 paramètres et reservation de 2 fois 8 octets (non utilisés ici).
En fin de procédure, le leave (pendant du enter) restaure la pile à partir de bsp et donc il est inutile de libérer l'espace pris par les alignements. enfin la procédure se termine par l'instruction ret 16 pour tenir compte du push des 2 paramètres.
Voilà voilà !!!
L'instruction enter contient une instruction push rsp qui va déphaser la pile de 8 octets et donc après cette instruction il faudra réaligner la pile (ne pas oublier les 8 octets du call et les 8 octets du push du parametre).
Mais attention, l'instruction enter sert dans son premier paramètre à réserver de la place pour stocker des données locales à la procédure (bien utile en cas d'appel récursif de la procédure). Si nous réservons 8 octets par exemple et bien nous déphasons de nouveau la pile de 8 octets et donc nous devrons gérer son impact.
Globalement si nous avons un nombre de paramètres plus le nombre de réservation de 8 octets de variable locales impair , nous devons réaligner la pile . Si ce nombre est pair, il ne faut pas la réaligner.
Voyons 2 exemples :
Passage de 2 paramètres et réservation de place par enter :
- Code:
;hello3.asm programme verification alignement de la pile
; apres passage parametre par push et instruction enter
global Main
extern ExitProcess,MessageBoxA,GetLastError,wsprintfA ; fonction API windows
MB_OK equ 000h
MB_OKCANCEL equ 001h
MB_ICONERROR equ 010h
MB_ICONINFORMATION equ 040h
;==============================================
;données initialisées
;==============================================
section .data
szTitre: db 'Win64', 0
szTitreErreur: db 'Win64', 0
szMsg: db 'Hello world!', 0
szMsg1 db "Appel ok",0
szMsgErreur db "Erreur N° %d",0
;==============================================
; données non initialisées
;==============================================
section .bss
szZoneRep resb 80
section .text
Main:
sub rsp, 28h
mov rcx, 0 ; handle fenêtre
lea rdx,[szMsg] ; adresse du message
lea r8,[szTitre] ; adresse du titre de la fenêtre
mov r9, MB_OK|MB_ICONINFORMATION ; type du message : OK
call MessageBoxA
push szTitre
push szMsg1 ; passage de 2 parametres
call appel
mov rcx,rax ; code retour avec le code retour de MessageBoxA
call ExitProcess ; fonction de fin du programme
;=================================================================
; verification lors de l'appel
;=================================================================
appel:
enter 8,0 ; réserve 8 octets pour utilisation locale
sub rsp,8h ; nous avons 2 push + une reservation = 3 impair donc la pile doit être alignée
sub rsp,20h ; réservation place des 4 parametres
mov rcx, 0 ; handle fenêtre
mov rdx,[rbp+16] ; adresse du message contenu dans la pile de base
mov r8,[rbp+24] ; adresse du titre de la fenêtre (1er parametre)
mov r9, MB_OK ; Normal
call MessageBoxA
cmp rax,0
jne .fin
call afferreur
.fin:
leave ; remet la pile en place à partir de la pile de base
ret 16 ; RE ATTENTION nous avons passé Deux parametres de 8 octets
;=================================================================
; affichage du message d'erreur
;=================================================================
afferreur:
sub rsp,8h
sub rsp,20h
call GetLastError ;récupèration du code erreur dans le registre rax
mov rcx,szZoneRep ; zone de retour du formatage
mov rdx,szMsgErreur ; libellé du message
mov r8,rax ; code erreur
call wsprintfA ; on devrait tester aussi le code retour
mov rcx, 0 ; handle fenêtre
mov rdx,szZoneRep ; adresse du message
mov r8,szTitreErreur ; adresse du titre de la fenêtre
mov r9, MB_OKCANCEL|MB_ICONERROR ; type du message : Erreur
call MessageBoxA
.fin:
add rsp,28h
ret
Passage de 2 paramètres et reservation de 2 fois 8 octets (non utilisés ici).
- Code:
;hello4.asm programme verification alignement de la pile
; apres passage parametre par push et instruction enter
global Main
extern ExitProcess,MessageBoxA,GetLastError,wsprintfA ; fonction API windows
MB_OK equ 000h
MB_OKCANCEL equ 001h
MB_ICONERROR equ 010h
MB_ICONINFORMATION equ 040h
;==============================================
;données initialisées
;==============================================
section .data
szTitre: db 'Win64', 0
szTitreErreur: db 'Win64', 0
szMsg: db 'Hello world!', 0
szMsg1 db "Appel ok",0
szMsgErreur db "Erreur N° %d",0
;==============================================
; données non initialisées
;==============================================
section .bss
szZoneRep resb 80
section .text
Main:
sub rsp, 28h
mov rcx, 0 ; handle fenêtre
lea rdx,[szMsg] ; adresse du message
lea r8,[szTitre] ; adresse du titre de la fenêtre
mov r9, MB_OK|MB_ICONINFORMATION ; type du message : OK
call MessageBoxA
push szTitre
push szMsg1 ; passage de 2 parametres
call appel
mov rcx,rax ; code retour avec le code retour de MessageBoxA
call ExitProcess ; fonction de fin du programme
;=================================================================
; verification lors de l'appel
;=================================================================
appel:
enter 16,0 ; 2 reservations pour varaibles locales
;sub rsp,8h ; nous avons 2 push + 2 reservations pair donc La pile ne doit pas être alignée
sub rsp,20h ; réservation place des 4 parametres
mov rcx, 0 ; handle fenêtre
mov rdx,[rbp+16] ; adresse du message contenu dans la pile de base
mov r8,[rbp+24] ; adresse du titre de la fenêtre (1er parametre)
mov r9, MB_OK ; Normal
call MessageBoxA
cmp rax,0
jne .fin
call afferreur
.fin:
leave ; remet la pile en place à partir de la pile de base
ret 16 ; RE ATTENTION nous avons passé Deux parametres de 8 octets
;=================================================================
; affichage du message d'erreur
;=================================================================
afferreur:
sub rsp,8h
sub rsp,20h
call GetLastError ;récupèration du code erreur dans le registre rax
mov rcx,szZoneRep ; zone de retour du formatage
mov rdx,szMsgErreur ; libellé du message
mov r8,rax ; code erreur
call wsprintfA ; on devrait tester aussi le code retour
mov rcx, 0 ; handle fenêtre
mov rdx,szZoneRep ; adresse du message
mov r8,szTitreErreur ; adresse du titre de la fenêtre
mov r9, MB_OKCANCEL|MB_ICONERROR ; type du message : Erreur
call MessageBoxA
.fin:
add rsp,28h
ret
En fin de procédure, le leave (pendant du enter) restaure la pile à partir de bsp et donc il est inutile de libérer l'espace pris par les alignements. enfin la procédure se termine par l'instruction ret 16 pour tenir compte du push des 2 paramètres.
Voilà voilà !!!
Page 1 sur 1
Permission de ce forum:
Vous ne pouvez pas répondre aux sujets dans ce forum
|
|