Assembleur 64 avec le compilateur nasm
Vous souhaitez réagir à ce message ? Créez un compte en quelques clics ou connectez-vous pour continuer.
Le Deal du moment : -50%
-50% Baskets Nike Air Huarache Runner
Voir le deal
69.99 €

Premier programme : affichage d'un message

Aller en bas

Premier programme : affichage d'un message Empty Premier programme : affichage d'un message

Message par Admin Mar 29 Nov - 15:29

Nous allons examiner en détail ce premier programme qui vous a servi à tester l'installation des outils :
Code:

;programme fenetre windows en 64 bits
global Main
extern ExitProcess,MessageBoxA     ; fonction API windows

section .data
szTitre:  db 'Win64', 0
szMsg:    db 'Hello world!', 0

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, 0       ;  type du message : OK
    call MessageBoxA

    mov  rcx,rax     ; code retour avec le code retour de MessageBoxA
    call ExitProcess  ; fonction de fin du programme


La directive global précise au linker que la procèdure Main peut être appelée de l'extérieur et est bien sûr la procédure principale. Celle çi figure bien dans la section de code .text et porte bien le même nom que celle définie dans l'option /entry du linker.
Ensuite la directive extern précise les fonctions de l'API Windows qui seront utilisées. Ces fonctions sont très bien documentées sur les sites internet de Microsoft. Il suffit de taper leur nom dans un moteur de recherche et de choisir les liens function ou msdn.
Ah mais vous trouvez pas MessageBoxA !!!  C'est normal car la fonction s'appelle en fait MessageBox mais elle se décline en 2 sous fonctions MessageBoxW pour traiter les caractères unicode et MessageBoxA pour les caractères ANSI. Dans ce forum, nous n'utiliserons que les fonctions pour les caractères ANSI.
Le code de la fonction Main commence par l'instruction sub rsp,28h, ce qui correspond à une réservation de place de 40 octets sur la pile.
Quel est le but de cette instruction ? En programmation 64 bits, il est nécessaire de respecter une contrainte d'alignement de la pile sur une frontière de 16 octets  (en clair, cela veut dire que l'adresse de la pile doit toujours se terminer par 0) avant l'appel à une fonction.
Mais les adresses sont en 64 bits soit 8 octets ce qui veut dire que chaque instruction qui fait intervenir la pile (push, pop, call, enter, leave, ret etc) va déphaser la pile de 8 octets. Ce qui nous oblige à realigner la pile.
Ici le système d'exploitation a appelé notre programme par un call qui a stocké l'adresse de retour sur la pile et qui l'a déphasée de 8 octets. Donc nous devons réaligner  la pile de 8 octets. Ok mais il reste encore 32 octets à expliquer.
Il y a une deuxième contrainte à respecter : avant l'appel de fonctions de l'API windows, nous devons réserver la place de 4 paramètres de 8 octets chacun (qword) soit 32 octets soit 20h.
Bien, maintenant voyons le passage des paramètres à la fonction : contrairement à la programmation en 32 bits où les paramètres sont passés par push, ici nous passons les 4 premiers paramètres  dans les registres 64 bits dans l'ordre suivant rcx, rdx, r8 et r9.
La documentation nous indique la valeur des 4 paramètres à passer : rcx contiendra le handle de la fenêtre principale de windows (c'est 0), rdx l'adresse du message à afficher (ici, nous utilisons lea, mais mov rdx,szMsg fonctionne aussi bien). r8 contient le titre de la fenêtre du message et r9 le type de message. La documentation précise tous les types de message qui peuvent être utilisés sous forme de constantes (Information, erreur, bouton Ok ou Cansel à afficher etc.).  
Le registre rax contiendra toujours le code retour de la fonction et la documentation précise que s'il est égal à zéro, une erreur s'est produite et le code erreur peut être retrouvé par l'appel de la fonction GetLastError. Ici, nous ne le testons pas (mauvais habitude) et nous nous contentons de le retourner au programme principal en le mettant dans le registre rcx avant l'appel de la fonction ExitProcess.
L'appel de cette fonction est préférable à un simple ret car elle va terminer correctement notre programme, fermer tous les handles qui ont été utilisées, nettoyer les tas éventuels et arrêter les process lancés qui peuvent encore tourner.
Admin
Admin
Admin

Messages : 38
Date d'inscription : 28/11/2016

https://assembleur64.kanak.fr

Revenir en haut Aller en bas

Revenir en haut

- Sujets similaires

 
Permission de ce forum:
Vous ne pouvez pas répondre aux sujets dans ce forum