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 16-bits Assembleur Discussion :

[MASM]Petite demande d'aide


Sujet :

x86 16-bits Assembleur

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Janvier 2011
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2011
    Messages : 11
    Points : 6
    Points
    6
    Par défaut [MASM]Petite demande d'aide
    Bonjour à tous,
    c'est depuis peu que pour mes études j'ai commencé à manipuler le langage assembleur mais le problème c'est que j'y comprends pas grand chose, c'est pourquoi je viens vous demander de l'aide. J'ai lu un grand nombre de cours sur internet et je comprends un peu près l'histoire de registre de segment, de pile mais je ne sais pas du tout quoi mettre dans l'en-tête de mon programme. J'ai pu voir: ASSUME CS:CSEG DSSEG SS:SSEG et je ne sais pas à quoi ça correspond, de plus j'utilise RadASM et je ne vois pas quand je dois programmer sous un programme en .com ou en .exe .

    Pour finir voili un petit bout de code que j'ai fait pour afficher un message et en lire un, je sais pas si c'est très correct, si quelqu'un me le corrigerai se serai super :p :

    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
     
    start:
     
    ;----------inscription du permier message
    MOV DX, OFFSET MESSAGE
    MOV AH, 09H
    INT 21H
    ;----------lecture du chiffre
    MOV DX, OFFSET TAMPON
    MOV AH, 3FH
    MOV CX, 50
    MOV BX, 0001h
    INT 21h
     
     
    ; exit to DOS
     
     
    mov ax, 4c00h
    int 21h
    TAMPON DB " "
    MESSAGE DB "Pour faire un calcule, vous etes au bon endroit!",0DH,0AH,24h
    code ends
     
    end start

    Edit: Merci pour le déplacement dans le forum adéquat.

    Merci d'avance

  2. #2
    Membre régulier
    Profil pro
    Inscrit en
    Novembre 2010
    Messages
    59
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2010
    Messages : 59
    Points : 88
    Points
    88
    Par défaut
    ASSUME CS:CSEG, DS:DSEG, SS:SSEG
    Déjà, je devine qu'il s'agit d'un programme EXE avec la pile dans un segment indépendant. CSEG est un segment de code car pointé par CS, DSEG est un segment de données car pointé par DS et SSEG est le segment de pile.
    Ensuite, il faut savoir que la directive ASSUME renseigne impérativement l'assembleur MASM sur le segment que pointe le registre de code CS, puis éventuellement, sur le registre de segment à employer lorsqu'il rencontre une référence de donnée sans préfixe de segment (ES: par exemple) et enfin, dans le cas d'un programme EXE, sur le segment qui contiendra la pile.

    Quant à l'emploi du format COM, on le réserve aux programmes simples et aux TSR.


    P.S. : dans un programme au format COM, code et données sont dans le même segment, la pile est à la fin. De plus, son exécution commence à l'offset 100h juste après le PSP créé par DOS et pointé par CS.
    Dans l'exemple suivant, on omet DS de la directive ASSUME :
    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
     
    CODE    SEGMENT
            ASSUME  CS:CODE
            ORG     100h    ; Offset suivant le PSP
     
    Depart:
            jmp     Debut
     
    VAR1    db      ?
     
    Debut:
            mov     VAR1,1  ; MASM traduit par CS:VAR1
            mov     VAR2,1  ; Err.6 - Phase error between passes
     
            ret             ; Fin
     
    VAR2    db      ?
     
    CODE    ENDS
     
            END     Depart
    L'assembleur MASM est obligé d'utiliser CS à la place de DS. Or, MASM n'a pas encore rencontré VAR2 lorsqu'il doit traduire l'instruction l'employant. Il faudrait ajouter explicitement un préfixe (CS: ou DS:).
    C'est un problème dû au fonctionnement de cet outil à deux passes.

  3. #3
    Futur Membre du Club
    Profil pro
    Inscrit en
    Janvier 2011
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2011
    Messages : 11
    Points : 6
    Points
    6
    Par défaut
    Ok merci je comprends un peu mieu

  4. #4
    Membre régulier
    Profil pro
    Inscrit en
    Novembre 2010
    Messages
    59
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2010
    Messages : 59
    Points : 88
    Points
    88
    Par défaut
    Vous voyez que l'idéal est d'utiliser le registre DS :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
            ASSUME  CS:CODE, DS:CODE
    Lorsque DS est utilisé implicitement, la position de VAR2 est indifférente pour MASM ; veillons toutefois à éviter que le programme ne se branche sur des données -- d'où le saut par dessus VAR1 en début de programme.
    MASM assumera que MOV VAR2,1 signifie MOV DS:VAR2,1. D'ailleurs, si vous observez le programme avec l'option U de DEBUG, vous remarquerez que le processeur lui-même ne nécessite de préfixe DS: car il s'agit du registre par défaut pour désigner une zone mémoire.
    Ensuite, rien n'empêche de déclarer explicitement le registre de segment tant qu'il pointe le bon segment :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    ; dans l'exemple précédent,
            MOV     CS:VAR2,1
    ; ou
            MOV     DS:VAR2,1
    Une obligation pour un programme EXE, il doit lui-même initialiser la valeur de DS :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
            MOV     AX,DSEG
            MOV     DS,AX
    En conclusion, ASSUME ne sert qu'à renseigner l'assembleur MASM des registres de segment à utiliser.
    Il incombe au programmeur de vérifier que ces derniers pointent bien les segments en question.

  5. #5
    Futur Membre du Club
    Profil pro
    Inscrit en
    Janvier 2011
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2011
    Messages : 11
    Points : 6
    Points
    6
    Par défaut
    Ok, et il me suffira de faire

    mov var1, DSEG
    Pour que ma variable soit stocké ?
    Et comment je pourrais faire pour convertir une chaine de caractère en nombre pour pouvoir utiliser la fontion 9 de l'interruption 21 en lecture de chaine, et pour après pouvoir faire un calcule ?

  6. #6
    Membre régulier
    Profil pro
    Inscrit en
    Novembre 2010
    Messages
    59
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2010
    Messages : 59
    Points : 88
    Points
    88
    Par défaut
    Vous avez l'air de vous embrouillez.
    Il serait bon d'étudier un petit programme au format EXE.
    Tout d'abord, on sait que grâce à l'en-tête, DOS initialise CS sur le segment de code où commence le programme, SS sur le segment contenant la pile. Néanmoins, il ne peut pas savoir quel est le segment de données courant.
    DS & ES pointent alors le PSP. Or, le PSP début par un appel à INT 20h. Lorsque cette interruption est appelée avec CS pointant le PSP, le programme se termine d'une manière compatible avec DOS 1.x.
    Ce qui donne en pratique :
    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
     
    ; EX.ASM
    ; Obtient la valeur représentée par un caractère ASCII stocké dans le prgm.
    ;       MASM    EX;
    ;       LINK    EX;
     
    DGROUP  GROUP   CSEG, DSEG
     
     
    CSEG    SEGMENT
            ASSUME  CS:CSEG, DS:DGROUP, SS:DGROUP
     
    PRINC   PROC    FAR
            push    ds
            xor     ax,ax
            push    ax      ; Laisse l'adresse complète du PSP sur la pile
     
            mov     ax,DSEG
            mov     ds,ax
     
            mov     dx,offset Chiffre
            call    LireChiffreDec
            ; à présent, DL contient la val. de la chaîne représentant le nb déc.
     
            ret             ; Retour lointain car PROCédure FAR
                            ; Vu que l'adresse du PSP est stockée sur la pile, fin
    PRINC   ENDP
     
    ; Lit un caractère ASCII supposé représenter un chiffre à l'adresse DS:DX
    ; avant de renvoyer la valeur dans DL.
    LireChiffreDec  PROC
            push    bx      ; Sauve BX
     
            mov     bx,dx   ; BX contient l'adresse du chiffre
            mov     dl,[bx] ; Un des rôles particuliers du registre BX
            sub     dl,30h  ; Obtient la valeur du chiffre représenté en ASCII
     
            pop     bx      ; Restitue BX
            ret
    LireChiffreDec  ENDP
     
    CSEG    ENDS
     
     
    DSEG    SEGMENT
     
    Chiffre DB      '2'
     
    DSEG    ENDS
     
     
    PILE    SEGMENT STACK   BYTE    ; Lié au segment préc. par BYTE
     
            DB      255 DUP (?)
     
    PILE    ENDS
     
     
            END     PRINC   ; Là où commence le programme
    La pile est située à la fin du segment de données.
    On a combiné les données et la pile dans un même segment DGROUP grâce à la directive GROUP.
    L'assembleur MASM utilise la directive END pour savoir où débute le programme et apporte les informations nécessaire pour l'en-tête du futur programme EXE.
    L'attribut STACK indique la pile.
    L'attribut BYTE indique que PILE ne débute pas un paragraphe mais l'octet suivant DSEG. PILE ne peut plus être considéré comme un segment. Ce programme EXE utilise un modèle de mémoire Small : un segment de code et un segment de données (la pile se trouvant dans ce dernier).
    Remarquez la conversion du caractère ASCII (devant être compris entre 0 et 9) en valeur. Observez la sauvegarde des registres ne servant pas à passer des paramètres ainsi que l'usage de BX pour lire une cellule de mémoire.

    Si vous comprenez ce programme, on peut passer à des choses plus pointues.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
             ___________
            |   Pile    |
            |           |
            | - - - - - |
            |           |
    Données |-----------| DGROUP (données)
            |           |
            |           |
    Code    |-----------| CSEG   (code)
    PSP     |___________|
    Figure - Programme EXE en mémoire, modèle SMALL.

  7. #7
    Futur Membre du Club
    Profil pro
    Inscrit en
    Janvier 2011
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2011
    Messages : 11
    Points : 6
    Points
    6
    Par défaut
    Merci beaucoup, je vais essayer de bien le comprendre.

  8. #8
    Membre régulier
    Profil pro
    Inscrit en
    Novembre 2010
    Messages
    59
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2010
    Messages : 59
    Points : 88
    Points
    88
    Par défaut
    Si quelque chose vous chagrine, n'hésitez pas à poser des questions.
    Je pense que vous comprenez que faire pointer DS sur DGROUP au lieu de DSEG revient au même.
    En revanche, j'ai oublié de préciser que la directive ASSUME doit suivre la déclaration du segment de code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    CODE    SEGMENT
            ASSUME  CS:CODE, DS:CODE
    L'architecture des 808x ou des 80x86 en mode réel est quelque peu casse-tête, mais c'est excellent pour la gymnastique cérébrale ! Le problème est que la manière d'utiliser MASM n'est pas si bien documentée sur Internet, surtout son ancienne syntaxe avec déclaration complète des segments.

  9. #9
    Futur Membre du Club
    Profil pro
    Inscrit en
    Janvier 2011
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2011
    Messages : 11
    Points : 6
    Points
    6
    Par défaut
    Oui je comprends, c'est très gentil de votre part. C'est vrai que la documentation c'est pas trop ça, en plus que les seul document existant sont assez vieux et donc assez difficile à comprendre au premier coup d'œil :s

    Merci beaucoup.

  10. #10
    Membre régulier
    Profil pro
    Inscrit en
    Novembre 2010
    Messages
    59
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2010
    Messages : 59
    Points : 88
    Points
    88
    Par défaut
    Comme l'a écrit JML19 dans un sujet précédent, DOS propose la fonction Ah pour l'entrée d'une chaîne de caractères. Ce service utilise le tampon pointé par DS:DX. Le premier octet indique le nombre de caractères disponibles. L'entrée est validée par la touche du même nom. Surtout ne pas oublier que le retour chariot (ASCII 13) est écrit après le tampon utilisé par le DOS : prévoir un octet supplémentaire.
    Le premier octet disponible indique le nombre de caractères entrés inscrits à la suite.
    Dans le petit exemple que je propose, j'ai scindé le tampon en deux parties successives pour illustrer l'emploi de MASM : TeteTampon et Tampon. TeteTampon termine le segment CODE, Tampon débute le pseudo-segment DATA? déclaré BYTE pour éviter de commencer à un nouveau paragraphe. TeteTampon et Tampon restent donc consécutifs.
    DATA? regroupe toutes les données n'ayant pas besoin d'être initialisées (d'être écrites dans le programme). Elles sont sous la forme suivante :
    Grâce à la directive GROUP, les données dans CODE et DATA? sont considérées être dans le même et unique segment du programme au format COM : CGROUP. Attention toutefois à la pseudo-instruction OFFSET appliquée à une donnée se trouvant dans DATA?. En l'absence de préfixe de segment, l'offset se basera sur le début de DATA? et non de CODE :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
            mov     si,offset ds:Tampon+1
    ; de préférence à
            mov     si,offset Tampon+1
    Voyons ce que l'utilisateur a à effectuer.
    Il entre un nombre entier au format décimal. La fourchette va de -2.147.483.648 à 2.147.486.647 car le nombre sera stocké dans un double-mot et sera considéré signé.
    Je n'ai pas réalisé de procédure pour mettre en forme le nombre donné par l'utilisateur. Il devra taper l'éventuel signe négatif suivi seulement des chiffres avant d'appuyer sur la touche Entrée.
    Toutes les procédures possèdent un en-tête d'explicatif.
    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
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
     
    ;       MASM    DEC2HEX;
    ;       LINK    DEC2HEX;
    ;       EXE2BIN DEC2HEX DEC2HEX.COM
     
     
    CGROUP  GROUP   CODE, DATA?
     
     
    LgNombre        equ     11
     
     
    CODE    SEGMENT
            ASSUME  CS:CODE, DS:CGROUP
            ORG     100h
     
    Depart:
            mov     Somme,0                 ; Initialise le double-mot Somme
            mov     Somme+2,0
            mov     ah,9                    ; Affiche message
            mov     dx,offset MsgEntree
            int     21h
            mov     ah,0Ah                  ; Attend entrée
            mov     dx,offset TeteTampon
            int     21h
            call    LireDecimalSgn
            jnc     Sortie                  ; Si pas d'erreur, sortie hexa
     
            cmp     ax,1                    ; Erreur de frappe ?
            jne     Err2
            mov     ah,9
            mov     dx,offset MsgTypo
            int     21h
            jmp     Depart                  ; Recommencez entrée
    Err2:
            cmp     ax,2                    ; Erreur de débordement ?
            jne     fin                     ; Si inégal, erreur inconnue
            mov     ah,9
            mov     dx,offset MsgDebord
            int     21h
            jmp     Depart                  ; Recommencez entrée
    Sortie:
            mov     ah,9
            mov     dx,offset MsgSortie
            int     21h
            std                             ; Direction : décrémentation
            mov     cx,4                    ; Double-mot (4 octets)
            mov     si,offset ds:Somme+3    ; Octet de poids fort
    Affiche_octet:
            lodsb                           ; AL = DS:[SI]  et  DEC SI
            call    AfficheHexa             ; Affiche les 2 chiffres hexa
            loop    Affiche_octet
    Fin:
            ret                             ; Fin
     
    LireDecimalSgn  PROC
    ; Lit le nombre décimal dans la chaîne Tampon avant de le traduire dans le
    ; double-mot Somme.
    ; Entrée :      DS:SI   pointe la chaîne dont le 1er octet donne le nb de car.
    ; Sortie :      Si succès, bit de retenue effacé et AX = 0
    ;               Si échec, bit de retenue positionné, AX = code d'erreur
    ;               Code d'erreur : 1, erreur de frappe
    ;                               2, erreur de débordement
    ; Lit :         Tampon
    ;               [1er car. : nb de car. (éventuel sgn "-" puis chiffres)]
    ; Ecrit :       Somme (double-mot)
    ; Procédure utilisée :  PuissDix
            push    bx
            push    cx
            push    dx
            push    si
            pushf                           ; sauve le registre d'état car CLD
     
            cld                             ; Direction : incrémentation
            xor     ch,ch                   ; CH = 0
            mov     cl,Tampon               ; Nb de caractères
            mov     si,offset ds:Tampon+1   ; DS:SI pointe le premier caractère
            cmp     byte ptr [si],'-'       ; Négatif ?
            jne     Boucle
            dec     cx
            inc     si
    Boucle:
            lodsb                           ; AL = DS:[SI]  et  INC SI
            cmp     al,'0'
            jb      Err_typo
            cmp     al,'9'
            ja      Err_typo
            sub     al,'0'                  ; Valeur du chiffre dans AL
     
            xor     ah,ah                   ; AH = 0
            xor     dx,dx                   ; DX = 0
            dec     cx                      ; Exposant = compteur - 1
            call    PuissDix                ; DX:AX = (DX:AX).10^CX
            jc      Err_debord1             ; Erreur ?
            or      dx,dx
            js      Err_debord1             ; Nb négatif ?
            inc     cx
     
            add     Somme,ax                ; Addition des mots de poids faible
            adc     Somme+2,dx              ; Add. avec retenue des mots de pds fort
            jc      Err_debord1             ; Retenue ?
            jo      Err_debord2             ; Débordement ?
            loop    Boucle                  ; Déc. CX et recommence si non nul
     
            cmp     Tampon+1,'-'
            jne     Retour_bon
            neg     Somme                   ; Complément à 2 du mot de poids faible
            not     Somme+2                 ; Complément à 1 du mot de poids fort
    Retour_bon:
            xor     ax,ax
            popf
            clc                             ; CF = 0
    Retour_mauvais:
            pop     si
            pop     dx
            pop     cx
            pop     bx
            ret
    Err_typo:
            mov     ax,1
            jmp     short Erreur
    Err_debord2:
            cmp     word ptr Somme,0
            jne     Err_debord1
            cmp     word ptr Somme+2,8000h
            jne     Err_debord1
            cmp     Tampon+1,'-'
            je      Retour_bon              ; Plus petit nombre possible
    Err_debord1:
            mov     ax,2
    Erreur:
            popf
            stc                             ; CF = 1
            jmp     Retour_mauvais
     
    LireDecimalSgn  ENDP
     
    PuissDix        PROC
    ; Stocke (DX:AX).10^CX dans DX:AX
    ; Entrée :      DX:AX   multiple
    ;               CX      exposant
    ; Sortie :      DX:AX   résultat de AL fois 10 puissance CX
            push    bx
            push    cx
            push    si
            push    di
     
            jcxz    Ret_PuissDix            ; Si CX nul, retour
            mov     bx,10                   ; BX : multiplicateur 10
            mov     si,dx                   ; SI <- poids fort
    FoisDix:
            xchg    di,ax                   ; DI <- poids faible
            xchg    ax,si                   ; AX <- poids fort
            mul     bx                      ; DX:AX (poids fort) = AX x 10
            or      dx,dx                   ; DX nul ?
            jnz     Debordement             ; Si non, erreur (32 bits insuff.)
            xchg    si,ax                   ; SI <- poids fort
            xchg    ax,di                   ; AX <- poids faible
            mul     bx
            add     si,dx                   ; Retenue dans le poids fort
            loop    FoisDix
     
            mov     dx,si                   ; DX <- poids fort
            clc                             ; CF = 0
    Ret_PuissDix:
            pop     di
            pop     si
            pop     cx
            pop     bx
            ret
    Debordement:
            stc                             ; CF = 1
            jmp     Ret_PuissDix
    PuissDix        ENDP
     
    AfficheHexa     PROC
    ; Affiche l'octet an AL sous forme de 2 chiffres hexa.
    ; Entrée :      AL      octet à afficher
    ; Procédure utilisée :  SortChiffreHexa
            push    ax
            push    cx
     
            mov     ah,al                   ; Sauve AL dans AH
            mov     cl,4
            shr     al,cl                   ; AL : quartet de poids fort
            call    SortChiffreHexa
            mov     al,ah                   ; Restitue AL
            and     al,0Fh                  ; AL : quartet de poids faible
            call    SortChiffreHexa
     
            pop     cx
            pop     ax
            ret
    AfficheHexa     ENDP
     
    SortChiffreHexa PROC
    ; Affiche un chiffre hexa stocké dans AL.
    ; Entrée :      AL      chiffre hexa
            push    ax
            push    dx
     
            add     al,90h
            daa
            adc     al,40h
            daa
            xchg    dx,ax                   ; DL <- AL
            mov     ah,2                    ; Affiche caractère
            int     21h
     
            pop     dx
            pop     ax
            ret
    SortChiffreHexa ENDP
     
    ; Données -------------------------------------------------------------------
     
    MsgEntree       db      13,10,'Entier décimal à convertir :',13,10,'$'
    MsgTypo         db      13,10,'Caractères autres que les chiffres et le signe '
                    db      '"-" refusés. Recommencez.$'
    MsgDebord       db      13,10,'Nombre hors limites. Recommencez.$'
    MsgSortie       db      13,10,'L',39,'équivalent hexadécimal est :',13,10,'$'
     
    ; Donne le nombre d'octets nécessaire à l'entrée du nombre pour DOS
    TeteTampon      db      LgNombre+1      ; Précède Tampon
     
    CODE    ENDS
     
    DATA?   SEGMENT BYTE
     
    ; Prend en compte l'enregistrement de la touche Entrée (car. 13)
    Tampon          db      LgNombre+2 dup(?) ; Suit TeteTampon
     
    Somme           dw      2 dup(?)
     
    DATA?   ENDS
     
            END     Depart
    Remarquons l'usage de l'instruction XCHG avec AX. Lorsque MASM la rencontre, elle l'optimise sous une forme qui ne nécessite qu'un octet (XCHG reg,AX) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
            xchg    ax,dx   ; 2 octets (87h C2h)
    ; se voit transformée ainsi par MASM :
            xchg    dx,ax   ; 1 octet (92h)
    C'est pourquoi je l'emploie à la place de MOV AX,reg ou MOV reg,AX lorsque les deux registres n'ont pas besoin de contenir la même valeur.

  11. #11
    Membre régulier
    Profil pro
    Inscrit en
    Novembre 2010
    Messages
    59
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2010
    Messages : 59
    Points : 88
    Points
    88
    Par défaut
    Je me rends compte que cette réponse aurait pu aider Med_be qui cherchait à entrer, lui, un entier non signé. Mon exemple ne lit pas un fichier (fct 3Fh) mais le clavier (fct 0Ah).
    Sa procédure PuissDix mérite quelques améliorations :
    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
     
    PuissDix        PROC
    ; Stocke (DX:AX).10^CX dans DX:AX
    ; Entrée :      DX:AX   multiple
    ;               CX      exposant
    ; Sortie :      Si bit de retenue effacé,
    ;               DX:AX   résultat de AL fois 10 puissance CX
    ;               Si bit de retenue positionné, débordement sur 32 bits,
    ;               DX et AX modifiés
            push    bx
            push    cx
            push    si
            push    di
     
            jcxz    Ret_PuissDix            ; Si CX nul, retour
            mov     bx,10                   ; BX : multiplicateur 10
            mov     si,dx                   ; SI <- poids fort
    FoisDix:
            xchg    di,ax                   ; DI <- poids faible
            xchg    ax,si                   ; AX <- poids fort
            mul     bx                      ; DX:AX (poids fort) = AX x 10
            jc      Ret_PuissDix            ; Si DX <> 0, erreur (32 bits insuff.)
            xchg    si,ax                   ; SI <- poids fort
            xchg    ax,di                   ; AX <- poids faible
            mul     bx
            add     si,dx                   ; Retenue dans le poids fort et CF=0
            loop    FoisDix
     
            mov     dx,si                   ; DX <- poids fort
    Ret_PuissDix:
            pop     di
            pop     si
            pop     cx
            pop     bx
            ret
    PuissDix        ENDP
    Quant à la syntaxe optimisée de XCHG reg,AX, je la donne à titre d'exemple car elle est valable avec l'outil de mise au point DEBUG mais pas avec SID. Ce dernier considère la forme inverse : XCHG AX,reg.
    Un assembleur tel MASM ôte ce souci.


    P.S. : l'en-tête de la longue procédure LireDecimalSgn est erroné. Elle ne nécessite pas de registre d'entrée, elle lit directement la chaîne Tampon.
    Néanmoins, pour rendre cette procédure réellement réutilisable, on peut lui demander de lire une chaîne quelconque à l'adresse DS:SI.
    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
     
    LireDecimalSgn  PROC
    ; Lit le nombre décimal dans la chaîne avant de le traduire dans le
    ; double-mot Somme.
    ; Entrée :      DS:SI   pointe la chaîne
    ;               [1er car. : nb de car. (éventuel sgn "-" puis chiffres)]
    ; Sortie :      Si succès, bit de retenue effacé et AX = 0
    ;               Si échec, bit de retenue positionné, AX = code d'erreur
    ;               Code d'erreur : 1, erreur de frappe
    ;                               2, erreur de débordement
    ; Ecrit :       Somme (double-mot)
    ; Procédure utilisée :  PuissDix
            push    bx
            push    cx
            push    dx
            push    di
            pushf                           ; sauve le registre d'état car CLD
     
            cld                             ; Direction : incrémentation
            xor     ch,ch                   ; CH = 0
            mov     cl,[si]                 ; Nb de caractères
            inc     si                      ; DS:SI pointe le premier caractère
            mov     di,si                   ; Sauve ce pointeur dans DI
            cmp     byte ptr [si],'-'       ; Négatif ?
            jne     Boucle
            dec     cx
            inc     si
    Boucle:
            lodsb                           ; AL = DS:[SI]  et  INC SI
            cmp     al,'0'
            jb      Err_typo
            cmp     al,'9'
            ja      Err_typo
            sub     al,'0'                  ; Valeur du chiffre dans AL
     
            xor     ah,ah                   ; AH = 0
            xor     dx,dx                   ; DX = 0
            dec     cx                      ; Exposant = compteur - 1
            call    PuissDix                ; DX:AX = (DX:AX).10^CX
            jc      Err_debord1             ; Erreur ?
            or      dx,dx
            js      Err_debord1             ; Nb négatif ?
            inc     cx
     
            add     Somme,ax                ; Addition des mots de poids faible
            adc     Somme+2,dx              ; Add. avec retenue des mots de pds fort
            jc      Err_debord1             ; Retenue ?
            jo      Err_debord2             ; Débordement ?
            loop    Boucle                  ; Déc. CX et recommence si non nul
     
     
            cmp     byte ptr [di],'-'
            jne     Retour_bon
            neg     Somme                   ; Complément à 2 du mot de poids faible
            not     Somme+2                 ; Complément à 1 du mot de poids fort
    Retour_bon:
            xor     ax,ax
            popf
            clc                             ; CF = 0
    Retour_mauvais:
            pop     di
            pop     dx
            pop     cx
            pop     bx
            ret
    Err_typo:
            mov     ax,1
            jmp     short Erreur
    Err_debord2:
            cmp     word ptr Somme,0
            jne     Err_debord1
            cmp     word ptr Somme+2,8000h
            jne     Err_debord1
            cmp     byte ptr [di],'-'
            je      Retour_bon              ; Plus petit nombre possible
    Err_debord1:
            mov     ax,2
    Erreur:
            popf
            stc                             ; CF = 1
            jmp     Retour_mauvais
    LireDecimalSgn  ENDP
    Il reste alors à faire précéder l'appel de cette procédure par l'affectation à SI de l'offset de la chaîne Tampon :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
            mov     si,offset ds:Tampon     ; DS:SI pointe Tampon
            call    LireDecimalSgn

  12. #12
    Membre régulier
    Profil pro
    Inscrit en
    Novembre 2010
    Messages
    59
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2010
    Messages : 59
    Points : 88
    Points
    88
    Par défaut Correction d'un bug
    La procédure LireDecimalSgn stocke dans un premier temps la valeur absolue du nombre lu dans un double-mot. Si ce nombre est négatif, elle corrige le double-mot. Pour cela, elle remplace le poids faible par son complément à deux et le poids fort par son complément à un. Le bug est que si le poids faible est nul, le poids fort doit aussi être remplacé par son complément à deux. D'où l'ajout de quelques lignes entre les instructions NEG et NOT :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
            jnz     Reversible              ; Si poids faible nul,
            dec     Somme+2                 ; décrémentation du poids fort
    Reversible:
    On obtient le programme final suivant :
    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
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
     
    ; Demande l'entrée d'un nombre entier décimal pouvant être stocké dans un
    ; double-mot signé de 32 bits.
    ; Assemblage :
    ;       MASM    DEC2HEX;
    ;       LINK    DEC2HEX;
    ;       EXE2BIN DEC2HEX DEC2HEX.COM
     
     
    CGROUP  GROUP   CODE, DATA?
     
     
    LgNombre        equ     11
     
     
    CODE    SEGMENT
            ASSUME  CS:CODE, DS:CGROUP
            ORG     100h
     
    Depart:
            mov     Somme,0                 ; Initialise le double-mot Somme
            mov     Somme+2,0
            mov     ah,9                    ; Affiche message
            mov     dx,offset MsgEntree
            int     21h
            mov     ah,0Ah                  ; Attend entrée
            mov     dx,offset TeteTampon
            int     21h
            call    LireDecimalSgn
            jnc     Sortie                  ; Si pas d'erreur, sortie hexa
     
            cmp     ax,1                    ; Erreur de frappe ?
            jne     Err2
            mov     ah,9
            mov     dx,offset MsgTypo
            int     21h
            jmp     Depart                  ; Recommencez entrée
    Err2:
            cmp     ax,2                    ; Erreur de débordement ?
            jne     fin                     ; Si inégal, erreur inconnue
            mov     ah,9
            mov     dx,offset MsgDebord
            int     21h
            jmp     Depart                  ; Recommencez entrée
    Sortie:
            mov     ah,9
            mov     dx,offset MsgSortie
            int     21h
            std                             ; Direction : décrémentation
            mov     cx,4                    ; Double-mot (4 octets)
            mov     si,offset ds:Somme+3    ; Octet de poids fort
    Affiche_octet:
            lodsb                           ; AL = DS:[SI]  et  DEC SI
            call    AfficheHexa             ; Affiche les 2 chiffres hexa
            loop    Affiche_octet
    Fin:
            ret                             ; Fin
     
    LireDecimalSgn  PROC
    ; Lit le nombre décimal dans la chaîne Tampon avant de le traduire dans le
    ; double-mot Somme.
    ; Entrée :      DS:SI   pointe la chaîne dont le 1er octet donne le nb de car.
    ; Sortie :      Si succès, bit de retenue effacé et AX = 0
    ;               Si échec, bit de retenue positionné, AX = code d'erreur
    ;               Code d'erreur : 1, erreur de frappe
    ;                               2, erreur de débordement
    ; Lit :         Tampon
    ;               [1er car. : nb de car. (éventuel sgn "-" puis chiffres)]
    ; Ecrit :       Somme (double-mot)
    ; Procédure utilisée :  PuissDix
            push    bx
            push    cx
            push    dx
            push    si
            pushf                           ; sauve le registre d'état car CLD
     
            cld                             ; Direction : incrémentation
            xor     ch,ch                   ; CH = 0
            mov     cl,Tampon               ; Nb de caractères
            mov     si,offset ds:Tampon+1   ; DS:SI pointe le premier caractère
            cmp     byte ptr [si],'-'       ; Négatif ?
            jne     Boucle
            dec     cx                      ; Nombres de chiffres si négatif
            inc     si                      ; Pointe le premier chiffre
    Boucle:
            lodsb                           ; AL = DS:[SI]  et  INC SI
            cmp     al,'0'
            jb      Err_typo
            cmp     al,'9'
            ja      Err_typo
            sub     al,'0'                  ; Valeur du chiffre dans AL
     
            xor     ah,ah                   ; AH = 0
            xor     dx,dx                   ; DX = 0
            dec     cx                      ; Exposant = compteur - 1
            call    PuissDix                ; DX:AX = (DX:AX).10^CX
            jc      Err_debord1             ; Erreur ?
            or      dx,dx
            js      Err_debord1             ; Nb négatif ?
            inc     cx
     
            add     Somme,ax                ; Addition des mots de poids faible
            adc     Somme+2,dx              ; Add. avec retenue des mots de pds fort
            jc      Err_debord1             ; Retenue ?
            jo      Err_debord2             ; Débordement ?
            loop    Boucle                  ; Déc. CX et recommence si non nul
     
            cmp     Tampon+1,'-'            ; Rendre négatif ?
            jne     Retour_bon
            neg     Somme                   ; Complément à 2 du mot de poids faible
            jnz     Reversible              ; Si poids faible nul,
            dec     Somme+2                 ; décrémentation du poids fort
    Reversible:
            not     Somme+2                 ; Complément à 1 du mot de poids fort
    Retour_bon:
            xor     ax,ax
            popf
            clc                             ; CF = 0
    Retour_mauvais:
            pop     si
            pop     dx
            pop     cx
            pop     bx
            ret
    Err_typo:
            mov     ax,1
            jmp     short Erreur
    Err_debord2:
            cmp     word ptr Somme,0
            jne     Err_debord1
            cmp     word ptr Somme+2,8000h
            jne     Err_debord1
            cmp     Tampon+1,'-'
            je      Retour_bon              ; Plus petit nombre possible
    Err_debord1:
            mov     ax,2
    Erreur:
            popf
            stc                             ; CF = 1
            jmp     Retour_mauvais
     
    LireDecimalSgn  ENDP
     
    PuissDix        PROC
    ; Stocke (DX:AX).10^CX dans DX:AX
    ; Entrée :      DX:AX   multiple
    ;               CX      exposant
    ; Sortie :      DX:AX   résultat de AL fois 10 puissance CX
            push    bx
            push    cx
            push    si
            push    di
     
            jcxz    Ret_PuissDix            ; Si CX nul, retour
            mov     bx,10                   ; BX : multiplicateur 10
            mov     si,dx                   ; SI <- poids fort
    FoisDix:
            xchg    di,ax                   ; DI <- poids faible
            xchg    ax,si                   ; AX <- poids fort
            mul     bx                      ; DX:AX (poids fort) = AX x 10
            or      dx,dx                   ; DX nul ?
            jnz     Debordement             ; Si non, erreur (32 bits insuff.)
            xchg    si,ax                   ; SI <- poids fort
            xchg    ax,di                   ; AX <- poids faible
            mul     bx
            add     si,dx                   ; Retenue dans le poids fort
            loop    FoisDix
     
            mov     dx,si                   ; DX <- poids fort
            clc                             ; CF = 0
    Ret_PuissDix:
            pop     di
            pop     si
            pop     cx
            pop     bx
            ret
    Debordement:
            stc                             ; CF = 1
            jmp     Ret_PuissDix
    PuissDix        ENDP
     
    AfficheHexa     PROC
    ; Affiche l'octet an AL sous forme de 2 chiffres hexa.
    ; Entrée :      AL      octet à afficher
    ; Procédure utilisée :  SortChiffreHexa
            push    ax
            push    cx
     
            mov     ah,al                   ; Sauve AL dans AH
            mov     cl,4
            shr     al,cl                   ; AL : quartet de poids fort
            call    SortChiffreHexa
            mov     al,ah                   ; Restitue AL
            and     al,0Fh                  ; AL : quartet de poids faible
            call    SortChiffreHexa
     
            pop     cx
            pop     ax
            ret
    AfficheHexa     ENDP
     
    SortChiffreHexa PROC
    ; Affiche un chiffre hexa stocké dans AL.
    ; Entrée :      AL      chiffre hexa
            push    ax
            push    dx
                                            ; Ex. : 0Ah        |    00h 
            add     al,90h                  ;       9Ah        |    90h
            daa                             ;    (1)00h        |    90h
            adc     al,40h                  ;       41h        |    D0h
            daa                             ;       41h -> 'A' | (1)31h -> '0'
            xchg    dx,ax                   ; DL <- AL
            mov     ah,2                    ; Affiche caractère
            int     21h
     
            pop     dx
            pop     ax
            ret
    SortChiffreHexa ENDP
     
    ; Données -------------------------------------------------------------------
     
    MsgEntree       db      13,10,'Entier décimal à convertir :',13,10,'$'
    MsgTypo         db      13,10,'Caractères autres que les chiffres et le signe '
                    db      '"-" refusés. Recommencez.$'
    MsgDebord       db      13,10,'Nombre hors limites. Recommencez.$'
    MsgSortie       db      13,10,'L',39,'équivalent hexadécimal est :',13,10,'$'
     
    ; Donne le nombre d'octets nécessaire à l'entrée du nombre pour DOS
    TeteTampon      db      LgNombre+1      ; Précède Tampon
     
    CODE    ENDS
     
    DATA?   SEGMENT BYTE
     
    ; Prend en compte l'enregistrement de la touche Entrée (car. 13)
    Tampon          db      LgNombre+2 dup(?) ; Suit TeteTampon
     
    Somme           dw      2 dup(?)
     
    DATA?   ENDS
     
            END     Depart

Discussions similaires

  1. Demande d'aide pour la réalisation d'un petit jeu video
    Par Frank1010 dans le forum Développement 2D, 3D et Jeux
    Réponses: 2
    Dernier message: 08/09/2009, 07h59
  2. Demande d'aide pour une petite requete
    Par NounaM dans le forum SQL
    Réponses: 8
    Dernier message: 19/06/2009, 11h27
  3. [demande d'aide] Une petit jeu de tir en flash ?
    Par renax dans le forum Flash
    Réponses: 4
    Dernier message: 13/12/2008, 13h32
  4. demande d'aide pour petit prog
    Par steph555 dans le forum Débuter
    Réponses: 2
    Dernier message: 19/10/2008, 20h51
  5. Réponses: 12
    Dernier message: 10/05/2007, 09h18

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