1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
| ; **************************************
; ****************************************
; ** name : pouet.asm **
; ** platform : linux x86 **
; ** compile : nasm -f elf pouet.asm **
; ** ld pouet.o -o pouet **
; ****************************************
; **************************************
; ===========================
; quelques definitions utiles
; ===========================
%define __NR_exit 1
%define __NR_read 3
%define __NR_write 4
%define STDIN_FILENO 0
%define STDOUT_FILENO 1
; ======================
; quelques macros utiles
; ======================
; -----------------------------------------------
; execute un appel systeme avec 1 parametre (ebx)
;
%macro syscall2 2
mov eax, %1
mov ebx, %2
int 0x80
%endmacro
; ----------------------------------------------------------
; execute un appel systeme avec 3 parametres (ebx, ecx, edx)
;
%macro syscall4 4
mov eax, %1
mov ebx, %2
mov ecx, %3
mov edx, %4
int 0x80
%endmacro
; -------------------------------------------------------
; effectue la conversion alphabetique -> entier numerique
;
; prend 2 parametres :
; - l'adresse de la chaine qui represente le nombre a convertir (ex. nb1_str)
; la chaine doit obligatoirement terminer par un \n (0Ah ou 10 en decimal)
; - l'adresse d'un emplacement libre pour stocker le nombre
;
; modifie les registres eax, edx et esi
;
%macro atoi 2
mov esi, %1
xor eax, eax
xor edx, edx
%%loop:
mov dl, byte [esi] ; on recupere le caractere du chiffre courrant dans edx
cmp dl, 10 ; si dl contient un retour chariot on a fini de traiter la chaine
je %%finish
lea eax, [eax * 4 + eax] ; eax = eax * 5
add eax, eax ; eax = eax + eax, donc a l'arrivee on a multiplie eax par 10 avec ces deux lignes
add esi, 1 ; on incremente le pointeur sur la chaine pour passer au chiffre suivant
and dl, 0x0F ; c'est une astuce pour recuperer la valeur decimale du chiffre, ca s'explique par la representation binaire, on aurait pu faire un sub 48 a la place
add eax, edx ; on additionne la valeur du chiffre a eax (qui a ete multiplie par 10 avant remember ?)
jmp %%loop ; et on boucle
%%finish:
mov [%2], eax
%endmacro
; -------------------------------------------------------
; effectue la conversion entier numerique -> chaine ascii
;
; prend 3 parametres :
; - l'adresse du dword contenant le nombre a convertir
; - l'adresse d'un buffer libre pour stocker la chaine convertie
; - l'adresse d'un emplacement pour stocker la longueur de la chaine convertie
;
; modifie les registres eax, ebx, ecx et edi
;
%macro itoa 3
mov eax, [%1] ; on recupere le nombre la ou il est stocke
mov edi, %2 ; on recupere l'adresse du buffer de destination
mov ebx, 10 ; diviseur = 10
xor ecx, ecx
%%first_loop:
xor edx, edx
div ebx ; on divise eax par 10, le quotient va dans eax, le reste va dans edx
push dx ; on stocke le reste, sachant qu'en divisant par 10 a chaque fois on stocke les chiffres dans l'ordre inverse -> 3,2,1
inc cl ; longueur (de la chaine) = longueur + 1
test eax, eax ; tant que eax != 0, c'est a dire tant que qu'il y a un quotient qu'on peut diviser et nous donner un reste
jnz %%first_loop
mov [%3], ecx ; ecx contient la longueur de la chaine, on stocke la valeur pour pas la perdre
%%second_loop: ; la seconde boucle permet de convertir decimal -> ascii en ajoutant 48, et de remettre les chiffre dans l'ordre attendu (grace aux pop)
pop ax ; donc on recupere le dernier chiffre traite
or al, 00110000b ; on lui ajoute 48 (la encore c'est un peu astucieux)
mov byte [edi], al ; et on le stocke dans le buffer de destination, de gauche a droite donc dans l'ordre -> "123"
inc edi
loop %%second_loop ; jusqu'a ce que ecx = 0, c'est a dire qu'on ait traite toute la chaine
mov byte [edi], 0
%endmacro
; ============
; les sections
; ============
section .data
msg1: db "1er nombre: "
len1 equ $ - msg1
msg2: db "2eme nombre: "
len2 equ $ - msg2
msg3: db "resultat: "
len3 equ $ - msg3
msg4 db 10
len4 equ $ - msg4 ; lol...
section .bss
; ici on reserve de quoi stocker les chaines correspondantes aux differents nombres qu'on manipule
nb1_str: resb 4
nb2_str: resb 4
sum_str: resb 5
; tandis qu'ici on reserve de quoi stocker leur valeur, qui tiendra dans un registre, donc au maximum un dword
nb1_dec: resd 1
nb2_dec: resd 1
sum_dec: resd 1
; et ici on stockera la longueur de la chaine sum_str, c'est un nombre, on reserve un dword
sum_len: resd 1
; =================
; en avant Guingamp
; =================
section .text
global _start
_start:
syscall4 __NR_write, STDOUT_FILENO, msg1, len1 ; on affiche le premier message
syscall4 __NR_read, STDIN_FILENO, nb1_str, 4 ; on lit le premier nombre
atoi nb1_str, nb1_dec ; on convertit l'entree utilisateur
syscall4 __NR_write, STDOUT_FILENO, msg2, len2 ; on affiche le deuxieme message
syscall4 __NR_read, STDIN_FILENO, nb2_str, 4 ; on lit le deuxieme nombre
atoi nb2_str, nb2_dec ; on passe a la moulinette pareil que pour le premier
mov eax, [nb1_dec] ; on recupere le 1er nombre
mov ebx, [nb2_dec] ; on recupere le 2eme
add eax, ebx ; on additionne
mov [sum_dec], eax ; on stocke le resultat de l'addition
itoa sum_dec, sum_str, sum_len ; et on convertit, mais dans l'autre sens cette fois-ci
syscall4 __NR_write, STDOUT_FILENO, msg3, len3 ; enfin on affiche, le message d'abord
syscall4 __NR_write, STDOUT_FILENO, sum_str, [sum_len] ; suivi du resultat
syscall4 __NR_write, STDOUT_FILENO, msg4, len4 ; et du retour a la ligne
syscall2 __NR_exit, 0 ; et on quitte |
Partager