IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

x86 32-bits / 64-bits Assembleur Discussion :

[NASM Linux 15.04] Additionner deux nombres


Sujet :

x86 32-bits / 64-bits Assembleur

  1. #1
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2016
    Messages
    15
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2016
    Messages : 15
    Points : 17
    Points
    17
    Par défaut [NASM Linux 15.04] Additionner deux nombres
    Bonjour,
    je suis en train d'apprendre l'assembleur mais je suis bloqué. Je n'arrive pas à additionner 2 nombres. Pouvez-vous m'aider? Merci d'avance. Voici le code que j'ai réalisé:


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
     
    section .data
     
    msgnb: db "1er nombre?",10
    msgnbl:  equ $-msgnb
    msgnb2: db "2eme nombre?",10
    msgnbl2:  equ $-msgnb2
     
    section .bss
    nb: resb 4
    nb2: resb 4
    unite: resb 4
    unite2: resb 4
    sum: resb 4
     
     
     
    section .text
    	global _start
     
    	_start:
     
    	affichage_msg1:
    	mov eax,4
    	mov ebx,1
    	mov ecx,msgnb
    	mov edx,msgnbl
    	int 0x80
     
    	saisie_nb:
    	mov eax,3
    	mov ebx,0
    	mov ecx,nb
    	mov edx, 4
    	int 0x80
     
    	affichage_msg2:
    	mov eax,4
    	mov ebx,1
    	mov ecx,msgnb2
    	mov edx,msgnbl2
    	int 0x80
     
    	saisie_nb2:
    	mov eax,3
    	mov ebx,0
    	mov ecx,nb2
    	mov edx, 4
    	int 0x80
     
    	;accceder nieme valeur
     
     
    	addition:
    	mov ecx, [nb+2]
    	mov dword [unite],ecx
     
     
     
    	add dword [unite],unite2
    	sub dword [unite], 48
     
     
    	mov eax,4
    	mov ebx,1
    	mov ecx,unite
    	mov edx,1
    	int 0x80
     
     
     
    	;appel fonction exit
    	end:
    	mov ebx,0
    	mov eax,1
    	int 0x80

  2. #2
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2016
    Messages
    15
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2016
    Messages : 15
    Points : 17
    Points
    17
    Par défaut
    J'ai trouvé. Voici la partie du code que j'ai changé:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    addition:
    mov ecx, [nb+2]
     
     
    mov ebx, [nb2+2]
     
    add ecx,ebx
    sub ecx,48
    Meilleurs voeux à toi aussi!

  3. #3
    Expert éminent Avatar de BufferBob
    Profil pro
    responsable R&D vidage de truites
    Inscrit en
    Novembre 2010
    Messages
    3 035
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : responsable R&D vidage de truites

    Informations forums :
    Inscription : Novembre 2010
    Messages : 3 035
    Points : 8 400
    Points
    8 400
    Par défaut
    salut,

    merci à toi d'avoir notifié la solution n'oublie pas de mettre ton code entre les balises [code][/code] !

  4. #4
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2016
    Messages
    15
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2016
    Messages : 15
    Points : 17
    Points
    17
    Par défaut
    Bonjour, je suis perdu avec mon programme; J'essaye d'additionner 2 nombres à 3 chiffres. Le problème est qu'il affiche un mauvais caractère pour l'unité.
    Exemple:
    200 + 100 = 30&

    lorsque je modifie ces instructions:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    cmp ecx,58
    jle diz
     
    sub dword [unite],10
    mov dword [retenue], 1
    200 + 100 = 300 marche mais

    456 + 104 = 55:

    Merci d'avance. J'espère avoir été clair. Je mets le code entier:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
     
     
     
     
    section .data
     
    msgnb: db "1er nombre?",10
    msgnbl:  equ $-msgnb
    msgnb2: db "2eme nombre?",10
    msgnbl2:  equ $-msgnb2
    a: db "test"
    aln: equ $-a
     
    section .bss
    nb: resb 4
    nb2: resb 4
    unite: resb 4
    unite2: resb 4
    centaine: resb 4
    dizaine: resb 4
    retenue: resb 4
     
     
     
     
    section .text
    	global _start
     
    	_start:
     
    	affichage_msg1:
    	mov eax,4
    	mov ebx,1
    	mov ecx,msgnb
    	mov edx,msgnbl
    	int 0x80
     
    	saisie_nb:
    	mov eax,3
    	mov ebx,0
    	mov ecx,nb
    	mov edx, 4
    	int 0x80
     
    	affichage_msg2:
    	mov eax,4
    	mov ebx,1
    	mov ecx,msgnb2
    	mov edx,msgnbl2
    	int 0x80
     
    	saisie_nb2:
    	mov eax,3
    	mov ebx,0
    	mov ecx,nb2
    	mov edx, 4
    	int 0x80
     
    	;
    	mov ecx, [nb+2]
    	mov ebx, [nb2+2]
    	add ecx,ebx
    	sub ecx,48
    	mov dword [unite],ecx
     
     
     
     
     
    	mov dword [retenue],0
     
    	cmp ecx,58
    	jle diz
     
     
     
    	sub dword [unite],10
    	mov dword [retenue], 1
     
     
     
     
    	diz:
     
    	mov ecx, [nb+1]
    	mov ebx, [nb2+1]
    	add ecx,ebx
    	sub ecx,48
     
     
    	mov dword [retenue],0
     
    	cmp ecx,57
    	jle cent
     
    	add ecx,[retenue]
    	mov dword [dizaine],ecx
     
     
    	cent:
    	mov ecx, [nb]
    	mov ebx, [nb2]
    	add ecx,ebx
    	sub ecx,48
    	add ecx,[retenue]
    	mov dword [centaine],ecx
     
     
    	affichage:
    	mov eax,4
    	mov ebx,1
    	mov ecx,centaine
    	mov edx,1
    	int 0x80
     
    	mov eax,4
    	mov ebx,1
    	mov ecx,dizaine
    	mov edx,1
    	int 0x80
     
    	mov eax,4
    	mov ebx,1
    	mov ecx,unite
    	mov edx,1
    	int 0x80
     
     
     
     
     
    	;appel fonction exit
    	end:
    	mov ebx,0
    	mov eax,1
    	int 0x80

  5. #5
    Expert éminent Avatar de BufferBob
    Profil pro
    responsable R&D vidage de truites
    Inscrit en
    Novembre 2010
    Messages
    3 035
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : responsable R&D vidage de truites

    Informations forums :
    Inscription : Novembre 2010
    Messages : 3 035
    Points : 8 400
    Points
    8 400
    Par défaut
    salut,

    écrire dix instructions pour chaque chiffre de la somme n'est pas viable, si tu dois additionner un nombre à 3 chiffres et un nombre à 8 chiffres tu vas réserver 8 emplacements jusqu'au million ?
    il te faut une routine d'affichage, ça n'est pas très compliqué; tu as ta somme (dans le registre ESI par exemple), tu la divise par 10 -> tu stockes le quotient dans ESI et le reste de la division correspond au chiffre des unités que tu peux afficher immédiatement, et tu répètes ainsi l'opération jusqu'à qu'il ne reste plus de chiffre (quand ESI vaut 0)

    d'autre part je t'encourages vivement à commenter ton code et/ou à mettre des define, on connait rarement par coeur le numéro de tous les syscalls

  6. #6
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2016
    Messages
    15
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2016
    Messages : 15
    Points : 17
    Points
    17
    Par défaut
    Salut,

    je vais appliquer tes conseils. Merci encore.

  7. #7
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2016
    Messages
    15
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2016
    Messages : 15
    Points : 17
    Points
    17
    Par défaut
    J'ai ajouté la macro pour afficher mais après je ne vois pas trop comment faire calculer la somme des 2 nombres. Je dois d'abord compter la taille du nombre que saisit l'utilisateur mais je ne vois pas trop comment faire. J'essaie de parcourir la chaîne chiffre par chiffre mais il me retourne segmentation fault.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    section .data
     
    msgnb: db "1er nombre?",10
    msgnbl:  equ $-msgnb
    msgnb2: db "2eme nombre?",10
    msgnbl2:  equ $-msgnb2
     
    section .bss
    nb: resb 4
    nb2: resb 4
    sum: resb 4
     
     
     
    %macro afficher 2
    	mov eax,4
    	mov ebx,1
    	mov ecx,%1
    	mov edx,%2
    	int 80h
    %endmacro
     
     
     
    section .text
    	global _start
     
    	_start:
     
    	afficher msgnb,msgnbl
     
    	saisie_premier_nb:
    	mov eax,3
    	mov ebx,0
    	mov ecx,nb
    	mov edx, 4
    	int 0x80
     
    	afficher msgnb2,msgnbl2
     
    	saisie_second_nb:
    	mov eax,3
    	mov ebx,0
    	mov ecx,nb2
    	mov edx, 4
    	int 0x80
     
    	afficher nb2,2
     
    	xor ecx,ecx
     
    	parcourt_nombre:
    	cmp dword [nb2+ecx],10
    	inc ecx
    	afficher nb2,ecx
    	jne parcourt_nombre
     
     
     
    	end:
    	mov ebx,0
    	mov eax,1
    	int 0x80

  8. #8
    Expert éminent Avatar de BufferBob
    Profil pro
    responsable R&D vidage de truites
    Inscrit en
    Novembre 2010
    Messages
    3 035
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : responsable R&D vidage de truites

    Informations forums :
    Inscription : Novembre 2010
    Messages : 3 035
    Points : 8 400
    Points
    8 400
    Par défaut
    tu sais coder en langage C ?

    tu lis les nombres entrés par l'utilisateur à travers le syscall read (man 2 read), ce que tu reçois dans le buffer c'est une chaine de caractères, pas directement un nombre utilisable pour une addition
    t'as deux choix possibles, soit tu continues à tout faire avec des syscalls uniquement et c'est à toi de faire une routine de conversion alpha -> num, soit tu fais appel à la libc dans ton code avec une fonction comme scanf par exemple qui se chargera de faire la conversion de manière transparente

  9. #9
    Expert éminent Avatar de BufferBob
    Profil pro
    responsable R&D vidage de truites
    Inscrit en
    Novembre 2010
    Messages
    3 035
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : responsable R&D vidage de truites

    Informations forums :
    Inscription : Novembre 2010
    Messages : 3 035
    Points : 8 400
    Points
    8 400
    Par défaut
    je te livre deux codes qui mettent en pratique ce que je te conseillais plus haut, l'un avec des syscalls, l'autre en utilisant les fonctions de la libc
    les deux codes sont structurés et -très largement- commentés tu devrais pouvoir t'y retrouver

    Code pouet.asm : Sélectionner tout - Visualiser dans une fenêtre à part
    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

    Code coin.asm : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    ;   **************************************
    ;  ****************************************
    ; ** name     :   coin.asm                **
    ; ** platform :   linux x86               **
    ; ** compile  :   nasm -f elf coin.asm    **
    ; **              gcc coin.o -o coin      **
    ;  ****************************************
    ;   **************************************
     
    ; ==============================================================
    ; on precise quelles sont les fonctions de la libc qu'on utilise
    ; ==============================================================
        extern printf
        extern scanf
     
    ; =======================
    ; on definit les sections
    ; =======================
    section .data
        msg1:       db "1er nombre: ", 0
        msg2:       db "2eme nombre: ", 0
        msg3:       db "resultat: "
        msg4:       db "%d", 0
        msg5:       db 10, 0
     
    section .bss
        nb1:    resd 1
        nb2:    resd 1
        sum:    resd 1
     
    ; ==========
    ; vroooom...
    ; ==========
    section .text
        global main
     
        main:
            push ebp            ; on s'installe confortablement avec un prologue standard
            mov ebp, esp
     
            push msg1
            call printf         ; on affiche le premier message
     
            push nb1
            push msg4
            call scanf          ; on attend la saisie du premier nombre
     
            push msg2
            call printf         ; on affiche le deuxieme message
     
            push nb2
            push msg4
            call scanf          ; on attend la saisie du deuxieme nombre
     
            mov eax, [nb1]
            mov ebx, [nb2]
            add eax, ebx        ; on effectue l'addition
            mov [sum], eax
     
            push dword [sum]
            push msg3
            call printf         ; on affiche le resultat a travers le 3eme message
     
            push msg5
            call printf         ; on finit en affichant un retour chariot, pour vider le tampon
     
            leave               ; et on quitte avec l'epilogue standard
            ret

  10. #10
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2016
    Messages
    15
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2016
    Messages : 15
    Points : 17
    Points
    17
    Par défaut
    Salut, merci beaucoup pour les codes car je galère.

    edit: avec la valeur 1444, il y a un segmentation fault.

    J'obtiens ces messages quand je compile le 2eme programme;
    :~/Bureau$ nasm -f elf -g 4.asm
    :~/Bureau$ gcc 4.o -o 4
    /usr/bin/ld: i386 architecture of input file `4.o' is incompatible with i38686-64 output
    collect2: error: ld returned 1 exit status

  11. #11
    Expert éminent Avatar de BufferBob
    Profil pro
    responsable R&D vidage de truites
    Inscrit en
    Novembre 2010
    Messages
    3 035
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : responsable R&D vidage de truites

    Informations forums :
    Inscription : Novembre 2010
    Messages : 3 035
    Points : 8 400
    Points
    8 400
    Par défaut
    tu compilais comment avant ? le premier code que tu as fournis tu utilises des syscalls 32bits, tu compilais sur la même machine ?

  12. #12
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2016
    Messages
    15
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2016
    Messages : 15
    Points : 17
    Points
    17
    Par défaut
    Non, j'ai utilisé cette commande: nasm -felf64 -g 4.asm. Et oui, je compile sur la même machine (linux).

  13. #13
    Expert éminent Avatar de BufferBob
    Profil pro
    responsable R&D vidage de truites
    Inscrit en
    Novembre 2010
    Messages
    3 035
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : responsable R&D vidage de truites

    Informations forums :
    Inscription : Novembre 2010
    Messages : 3 035
    Points : 8 400
    Points
    8 400
    Par défaut
    Edit:ça n'est pas possible, le code que tu as donné dans ton premier message ne compilera pas avec l'option -f elf64, et quand bien même ça compilerait ça n'a absolument aucune chance de s'exécuter, entre linux 32 et 64 bits les numéros des syscalls ne sont pas les mêmes, t'as du te fourvoyer quelque part
    au temps pour moi je viens de vérifier et ça fonctionne, on peut trouver un début d'explication ici, en gros quand on utilise int 80h on utilise automatiquement la table de syscalls 32bits, considérant que le mécanisme pour 64bits passe résolument par systenter/syscall j'imagine, mea culpa ^^

    du coup t'as essayé avec -f elf32 ? du coup tu compiles quand même du code fait pour une machine 32bits en un binaire 64bits qui utilise des appels systèmes 32bits

    n'empêche que tu prends d'emblée de mauvaises habitudes si tu veux mon avis, tu ne commentes pas tes codes, tu codes 32bits sur une machine 64bits, et sauf erreur tu n'as aucune notion de langage C pour t'aider, ça va pas être facile

  14. #14
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2016
    Messages
    15
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2016
    Messages : 15
    Points : 17
    Points
    17
    Par défaut
    Avec elf 32, cela ne fonctionne pas non plus pour les 2 programmes. Le premier programme que j'ai réalisé fonctionnait avec la commande 64. Je connais le C mais je n'ai pas appris à appeler des fonctions c dans un code assembleur;

  15. #15
    Expert éminent Avatar de BufferBob
    Profil pro
    responsable R&D vidage de truites
    Inscrit en
    Novembre 2010
    Messages
    3 035
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : responsable R&D vidage de truites

    Informations forums :
    Inscription : Novembre 2010
    Messages : 3 035
    Points : 8 400
    Points
    8 400
    Par défaut
    tant qu'à faire de l'assembleur sur une machine 64bits, autant faire de l'assembleur 64bits.
    les deux même codes, en version 64bits donc :

    Code pouet64.asm : Sélectionner tout - Visualiser dans une fenêtre à part
    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     :   pouet64.asm             **
    ; ** platform :   linux x86_64            **
    ; ** compile  :   nasm -f elf64 pouet.asm **
    ; **              ld pouet.o -o pouet     **
    ;  ****************************************
    ;   **************************************
     
    ; ===========================
    ; quelques definitions utiles
    ; ===========================
    %define __NR_exit       60
    %define __NR_read       0
    %define __NR_write      1
     
    %define STDIN_FILENO    0
    %define STDOUT_FILENO   1
     
    ; ======================
    ; quelques macros utiles
    ; ======================
     
    ; -----------------------------------------------
    ; execute un appel systeme avec 1 parametre (rbx)
    ;
    %macro syscall2 2
        mov rax, %1
        mov rdi, %2
        syscall
    %endmacro
     
    ; ----------------------------------------------------------
    ; execute un appel systeme avec 3 parametres (rbx, rcx, rdx)
    ;
    %macro syscall4 4
        mov rax, %1
        mov rdi, %2
        mov rsi, %3
        mov rdx, %4
        syscall
    %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 rax, rdx et rsi
    ;
    %macro atoi 2
            mov rsi, %1
            xor rax, rax
            xor rdx, rdx
        %%loop:
            mov dl, byte [rsi]          ; on recupere le caractere du chiffre courrant dans rdx
            cmp dl, 10                  ; si dl contient un retour chariot on a fini de traiter la chaine
            je %%finish
            lea rax, [rax * 4 + rax]    ; rax = rax * 5
            add rax, rax                ; rax = rax + rax, donc a l'arrivee on a multiplie rax par 10 avec ces deux lignes
            add rsi, 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 rax, rdx                ; on additionne la valeur du chiffre a rax (qui a ete multiplie par 10 avant remember ?)
            jmp %%loop                  ; et on boucle
        %%finish:
            mov [%2], rax
    %endmacro
     
    ; -------------------------------------------------------
    ; effectue la conversion entier numerique -> chaine ascii
    ;
    ; prend 3 parametres :
    ; - l'adresse du qword 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 rax, rbx, rcx et rdi
    ;
    %macro itoa 3
            mov rax, [%1]               ; on recupere le nombre la ou il est stocke
            mov rdi, %2                 ; on recupere l'adresse du buffer de destination
            mov rbx, 10                 ; diviseur = 10
            xor rcx, rcx
        %%first_loop:
            xor rdx, rdx
            div rbx                     ; on divise rax par 10, le quotient va dans rax, le reste va dans rdx
            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 rax, rax               ; tant que rax != 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], rcx               ; rcx 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 [rdi], al          ; et on le stocke dans le buffer de destination, de gauche a droite donc dans l'ordre -> "123"
            inc rdi
            loop %%second_loop          ; jusqu'a ce que rcx = 0, c'est a dire qu'on ait traite toute la chaine
            mov byte [rdi], 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 corrrspondantes 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 qword
        nb1_dec:    resq 1
        nb2_dec:    resq 1
        sum_dec:    resq 1
     
        ; et ici on stockera la longueur de la chaine sum_str, c'est un nombre, on reserve un qword
        sum_len:    resq 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 rax, [nb1_dec]                              ; on recupere le 1er nombre
            mov rbx, [nb2_dec]                              ; on recupere le 2eme
            add rax, rbx                                    ; on additionne
            mov [sum_dec], rax                              ; 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

    Code coin64.asm : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    ;   **************************************
    ;  ****************************************
    ; ** name     :   coin64.asm              **
    ; ** platform :   linux x86_64            **
    ; ** compile  :   nasm -f elf64 coin.asm  **
    ; **              gcc coin.o -o coin      **
    ;  ****************************************
    ;   **************************************
     
    ; ==============================================================
    ; on precise quelles sont les fonctions de la libc qu'on utilise
    ; ==============================================================
        extern printf
        extern scanf
     
    ; =======================
    ; on definit les sections
    ; =======================
    section .data
        msg1:       db "1er nombre: ", 0
        msg2:       db "2eme nombre: ", 0
        msg3:       db "resultat: "
        msg4:       db "%d", 0
        msg5:       db 10, 0
     
    section .bss
        nb1:    resq 1
        nb2:    resq 1
        sum:    resq 1
     
    ; ==========
    ; vroooom...
    ; ==========
    section .text
        global main
     
        main:
            push rbp            ; on s'installe confortablement avec un prologue standard
            mov rbp, rsp
     
            push msg1
            call printf         ; on affiche le premier message
     
            push nb1
            push msg4
            call scanf          ; on attend la saisie du premier nombre
     
            push msg2
            call printf         ; on affiche le deuxieme message
     
            push nb2
            push msg4
            call scanf          ; on attend la saisie du deuxieme nombre
     
            mov rax, [nb1]
            mov rbx, [nb2]
            add rax, rbx        ; on effectue l'addition
            mov [sum], rax
     
            push qword [sum]
            push msg3
            call printf         ; on affiche le resultat a travers le 3eme message
     
            push msg5
            call printf         ; on finit en affichant un retour chariot, pour vider le tampon
     
            leave               ; et on quitte avec l'epilogue standard
            ret

    par rapport aux codes 32bits les principales différences résident dans :
    • les registres eax,ebx,ecx,... deviennent respectivement rax,rbx,rcx,...
    • la taille des emplacements de stockages dans le bss (uniquement pour des raisons de facilité ici), les resd deviennent des resq (qword, 64bits)
    • les numéros de syscalls (cf. les %define)
    • et surtout évidemment les macros permettant de faire les syscalls, où on change de convention d'appel (eax,ebx,ecx,edx,esi,edi... --> rax,rdi,rdx,rcx,r8,r9...) et de syscall gate (int 0x80 --> syscall)

  16. #16
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2016
    Messages
    15
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2016
    Messages : 15
    Points : 17
    Points
    17
    Par défaut
    Salut, merci pour ton aide.

    Autant pour moi pour le 1er programme, c'est parce que il y avait 4 pour la longueur du nombre.

    La deuxième version ne marche pas. J'arrive à compiler mais lorsque je le lance, il m'affiche un segmentation fault.

    Je ne comprends pas cette ligne:

    lea rax, [rax * 4 + rax]

    LEA manipule les adresses. Comment tu peux multiplier par 5?

  17. #17
    Expert éminent Avatar de BufferBob
    Profil pro
    responsable R&D vidage de truites
    Inscrit en
    Novembre 2010
    Messages
    3 035
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : responsable R&D vidage de truites

    Informations forums :
    Inscription : Novembre 2010
    Messages : 3 035
    Points : 8 400
    Points
    8 400
    Par défaut
    Citation Envoyé par Conan Edogawa Voir le message
    lea rax, [rax * 4 + rax]
    LEA manipule les adresses. Comment tu peux multiplier par 5?
    ben... imagine que rax contient une adresse au lieu de contenir le nombre entré par l'utilisateur ?

    je vois ce que tu veux dire mais pour le coup il n'y a pas à se casser la tête outre mesure en fait, tu prends rax * 4 + rax tu le mets dans rax ça va pas chercher plus loin

    tu pourrais considérer l'instruction comme un hypothétique mov rax, rax*4+rax, ce qui serait différent de mov rax, [rax*4+rax]
    donc ça s'écrit lea bla, [bla] mais ça revient au même qu'un mov bla, bla

  18. #18
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2016
    Messages
    15
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2016
    Messages : 15
    Points : 17
    Points
    17
    Par défaut
    Le programme assembleur avec les fonctions c m'affiche un segmentation fault.

  19. #19
    Expert éminent Avatar de BufferBob
    Profil pro
    responsable R&D vidage de truites
    Inscrit en
    Novembre 2010
    Messages
    3 035
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : responsable R&D vidage de truites

    Informations forums :
    Inscription : Novembre 2010
    Messages : 3 035
    Points : 8 400
    Points
    8 400
    Par défaut
    Citation Envoyé par Conan Edogawa Voir le message
    Le programme assembleur avec les fonctions c m'affiche un segmentation fault.
    quel code/quel fichier, celui en 32bits ? celui en 64bits ? à la compilation ? à l'exécution ? quand tu rentres un nombre comme "999" ? quand tu rentres un nombre comme "999999999" ? quand tu rentres du junk comme "f4h%56jj$*456-mg5_ç({6h8mjqrg" ?

  20. #20
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2016
    Messages
    15
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2016
    Messages : 15
    Points : 17
    Points
    17
    Par défaut
    Le second fichier 64 bits avec l'utilisation des fonctions scanf et printf ne s'execute pas et m'affiche un beau segmentation fault.

    Celui-là:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
     
    ;   **************************************
    ;  ****************************************
    ; ** name     :   coin64.asm              **
    ; ** platform :   linux x86_64            **
    ; ** compile  :   nasm -f elf64 coin.asm  **
    ; **              gcc coin.o -o coin      **
    ;  ****************************************
    ;   **************************************
     
    ; ==============================================================
    ; on precise quelles sont les fonctions de la libc qu'on utilise
    ; ==============================================================
        extern printf
        extern scanf
     
    ; =======================
    ; on definit les sections
    ; =======================
    section .data
        msg1:       db "1er nombre: ", 0
        msg2:       db "2eme nombre: ", 0
        msg3:       db "resultat: "
        msg4:       db "%d", 0
        msg5:       db 10, 0
     
    section .bss
        nb1:    resq 1
        nb2:    resq 1
        sum:    resq 1
     
    ; ==========
    ; vroooom...
    ; ==========
    section .text
        global main
     
        main:
            push rbp            ; on s'installe confortablement avec un prologue standard
            mov rbp, rsp
     
            push msg1
            call printf         ; on affiche le premier message
     
            push nb1
            push msg4
            call scanf          ; on attend la saisie du premier nombre
     
            push msg2
            call printf         ; on affiche le deuxieme message
     
            push nb2
            push msg4
            call scanf          ; on attend la saisie du deuxieme nombre
     
            mov rax, [nb1]
            mov rbx, [nb2]
            add rax, rbx        ; on effectue l'addition
            mov [sum], rax
     
            push qword [sum]
            push msg3
            call printf         ; on affiche le resultat a travers le 3eme message
     
            push msg5
            call printf         ; on finit en affichant un retour chariot, pour vider le tampon
     
            leave               ; et on quitte avec l'epilogue standard
            ret

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Additionner deux nombres en binaire
    Par laurecasier dans le forum Algorithmes et structures de données
    Réponses: 2
    Dernier message: 12/10/2015, 08h18
  2. Additionner deux String qui sont des nombres
    Par JDev_ dans le forum Requêtes et SQL.
    Réponses: 1
    Dernier message: 24/05/2012, 13h00
  3. Réponses: 5
    Dernier message: 13/04/2011, 17h59
  4. Additionner deux nombres à virgule
    Par renaud26 dans le forum Langage
    Réponses: 2
    Dernier message: 11/12/2007, 16h29

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo