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 :

Redirection de l'interruption 23h pour traiter le Ctrl-Break


Sujet :

x86 16-bits Assembleur

  1. #1
    Candidat au Club
    Femme Profil pro
    Étudiant
    Inscrit en
    Janvier 2011
    Messages
    25
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : Tunisie

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Janvier 2011
    Messages : 25
    Points : 2
    Points
    2
    Par défaut Redirection de l'interruption 23h pour traiter le Ctrl-Break
    Bonjour,

    je veux créer un programme qui redirige l'interruption 23h sur une routine à lui, de façon à garder le contrôle des événements meme lorsque CTRL+Break est actionnée. La nouvelle routine de gestion de l'interruption 23h se doit d'afficher à l'utilisateur un message lui demandant de confirmer l'arrêt d'un programme en cours d'éxécution, puis éventuellement de mettre fin proprement au programme.

    Voici le code, mais lors de l'exécution le programme ne marche pas correctement. Pouvez-vous m'aider svp ?
    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
    .model small
    .stack 100h
    .386
    .data
    v dw 32000
    vecteur dw ?
    message1 db 'bonjour',10,13,'$'
    message2 db 'souhaitez vous vraiment fermer le programme? (o/n)',10,13,'$'
    num_int db "23h"
    .code
    main proc
    mov ax,@data
    mov ds,ax
    mov cx,0
     
    Afficher_Bonjour:	
    mov ah,9
    lea dx,message1
    int 21h
    inc cx
    cmp cx,v
    jne Afficher_Bonjour
     
    Redirige_Int:
    mov al,23h
    mov ah,35h
    mov [vecteur],bx
    mov [vecteur+2],es
    lea dx,Traiter_Ctrl_Break
    mov al,23h
    mov ah,25h
    int 21h
     
    Traiter_Ctrl_Break:
    mov ah,9
    lea dx,message2
    int 21h
     
    verif1:
    mov ah,1
    int 21h
    cmp al,'o'
    jne verif2
    jmp Fin_Propre
     
    verif2:
    mov ah,1
    int 21h
    cmp al,'n'
    jne verif1
    jmp afficher_bonjour
     
    Fin_Propre:
    lea dx,retour
    mov al,23h
    mov ah,25h
    int 21h
     
    retour:
    mov bx,[vecteur]
    mov es,[vecteur+2]
     
    mov ah,4ch
    int 21h
     
    main EnDP
    EnD main;

  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 Handler Ctrl-C
    Voici les corrections à apporter :
    - enlever la directive .386 car il n'y a pas d'instruction 32 bits ;
    - lors du détournement d'interruption, DS doit pointer le segment de la nouvelle routine ;
    - déplacer la boucle d'affichage à la suite du détournement ;
    - restituer le vecteur de l'interruption 23h est inutile car DOS le fait après la fin du programme (de toute façon, il fallait préciser WORD PTR devant [vecteur] et [vecteur+2], remplacer LEA DX,retour par LDS DX,vecteur et vecteur dw ? par vecteur dd ?) ;
    - déplacer Traiter_Ctrl_Break dans une procédure lointaine (FAR) terminée par un IRET ou un RET 2 ;
    - supprimer l'étiquette retour et les deux lignes qui suivent car inutiles.

    Il est nécessaire de savoir ce qui se passe lorsqu'on détourne l'interruption 23h à l'aide du service 25h du DOS ou en écrivant directement à l'adresse 0:8Ch. Le vecteur de l'int 23h pointe une routine spéciale du DOS qui, après avoir déposé le registre FLAG sur la pile, fait un appel lointain à notre routine. Lorsque notre routine redonne la main au DOS, ce dernier analyse le bit de retenue (Carry Flag) : s'il est à 1, DOS termine notre programme ; s'il est à 0, un retour d'interruption est effectué. Tout cela, en théorie.
    Dans le programme que je propose en correction du vôtre, le handler Ctrl-C est, bien sûr, une procédure FAR.
    Je précise que les vecteurs des interruptions 22h à 24h sont restaurés par le DOS lorsqu'il termine un programme (leurs valeurs sont dans le PSP).
    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
     
    ; Requiert DOS 2 ou plus.
    .model small
    .stack 100h
     
     
    .data
    v               dw 32000
    message1        db 10,13,'bonjour$'
    message2        db 'souhaitez vous vraiment fermer le programme? (o/n)'
                    db 10,13,'$'
    num_int         db "23h"
     
     
    .code
    main    Proc
            mov     ax,@data
            mov     ds,ax
            mov     cx,v                    ; cx = v qui vaut 32000
     
    Redirige_Int:
            push    ds                      ; Sauve DS sur la pile
            push    cs                      ; DS = CS
            pop     ds                      ; car la routine fait partie du code
            lea     dx,Traiter_Ctrl_Break
            mov     al,23h
            mov     ah,25h
            int     21h
            pop     ds                      ; Restitue DS
     
            mov     ah,9
            lea     dx,message1
    Afficher_Bonjour:
            int     21h
            loop    Afficher_Bonjour        ; Déc. CX puis boucle si non nul
     
            ; Boucle achevée avec le compteur CX nul
    Fin:
            mov     ah,4ch
            int     21h
    main    EndP
     
    Traiter_Ctrl_Break      Proc    FAR     ; Appel lointain
    ; -----------------------------------------------------------------------------
    ; Procédure appelée par l'interruption 23h.
    ; Demande à l'utilisateur s'il veut terminer le programme après un Ctrl+Break.
    ; Entrée :      aucune (veillons toutefois que DS pointe le bon seg de données)
    ; Sortie :      aucune, l'état du bit de retenue (CF) étant traité par le DOS
    ; -----------------------------------------------------------------------------
    ; Les 12 derniers octets de la pile :
    ; offset DOS, segment DOS, FLAG, offset programme, segment programme, FLAG...
            push    ax                      ; Sauve les registres modifiés
            push    dx
     
    Question:
            mov     ah,9                    ; Affiche "Terminer ?"
            lea     dx,message2
            int     21h
            mov     ah,1                    ; Attend réponse
            int     21h
            cmp     al,'o'                  ; AL = 'o' ?
             jne    Non?
            stc                             ; CF=1, demande au DOS de terminer
             jmp    short Retour_int23      ; Oui, retour
    Non?:
            cmp     al,'n'                  ; Sinon, AL = 'n' ?
             jne    Question                ; Non, repose la question
            ; CF = 0 implicitement (égalité), demande au DOS de continuer
     
    Retour_int23:
            pop     dx                      ; Restitue les registres (pile LIFO :
            pop     ax                      ; Last Input, First Output)
            ret     2                       ; Registre FLAG non restitué
    Traiter_Ctrl_Break      EndP
     
            End     main
    L'handler se termine par un RETF 2 et non un IRET car on ne veut pas restituer le registre FLAG (dit aussi registre d'état) sauvé par le DOS. Si l'utilisateur avait répondu « o » à la question, le bit de retenue est positionné (CF = 1) et DOS mettra directement fin à notre programme. Si c'était « n », le bit de retenue est effacé (CF = 0) et DOS redonne la main au programme grâce à l'adresse sauvée sur la pile.

    Malheureusement, ce programme a été testé sous DR DOS. Au cas où le handler ne peut terminer le programme, on procède autrement car cela signifie que le DOS se fiche de l'état du bit de retenue.
    Premièrement, il faut ajouter les deux instructions suivantes au début du handler :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
            push    bp
            mov     bp,sp
    et celle-ci avant RET 2 :
    Deuxièmement, il faut connaître l'état de la pile après l'exécution des deux premières :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    [BP+12] FLAG lors de l'interruption 23h
    [BP+10]	segment de retour
     [BP+8] offset de retour
     [BP+6] FLAG lorsque DOS a appelé notre handler
     [BP+4] segment du DOS
     [BP+2] offset du DOS
       [BP] BP précédent.
    Troisièmement, on peut remplacer STC par :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
            mov     word ptr [bp+8],offset Fin
    Néanmoins, « bonjour » sera affiché une dernière fois avant la fin car la fonction DOS interrompue est recommencée.
    Il est donc préférable d'ajouter la nouvelle instruction après STC et les suivantes avant RET 2 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
            jnc     Retour_DOS              ; Retour au traitement du DOS
            add     sp,6                    ; Nettoie l'adresse de retour du DOS
    Retour_DOS:
    Enfin, on remplace RET 2 par IRET pour être sûr que l'état des drapeaux lors de l'interruption soit restauré. Notons que si l'utilisateur souhaite continuer le programme, le registre FLAG déposé par le DOS est restauré. L'état du bit de retenue n'a alors plus d'importance et on modifie, par conséquent, l'en-tête de la procédure.
    Ci-dessous, le handler obtenu :
    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
     
    Traiter_Ctrl_Break      Proc    FAR     ; Appel lointain
    ; -----------------------------------------------------------------------------
    ; Procédure appelée par l'interruption 23h. Les 12 derniers octets de la pile :
    ; offset DOS, segment DOS, FLAG, offset programme, segment programme, FLAG...
    ; Demande à l'utilisateur s'il veut terminer le programme après un Ctrl+Break.
    ; Entrée :      aucune (veillons toutefois que DS pointe le bon seg de données)
    ; Sortie :      aucune
    ; -----------------------------------------------------------------------------
    ; Les 12 derniers octets de la pile :
    ; offset DOS, segment DOS, FLAG, offset programme, segment programme, FLAG...
            push    bp                      ; Sauve les registres modifiés ne
                                            ; servant pas de paramètres de sortie
            mov     bp,sp                   ; BP + 8 pointe l'offset de retour
            push    ax
            push    dx
     
    Question:
            mov     ah,9                    ; Affiche "Terminer ?"
            lea     dx,message2
            int     21h
            mov     ah,1                    ; Attend réponse
            int     21h
            cmp     al,'o'                  ; AL = 'o' ?
             jne    Non?
            stc                             ; CF = 1
            mov     word ptr [bp+8],offset Fin
             jmp    short Retour_int23      ; Oui, retour
    Non?:
            cmp     al,'n'                  ; Sinon, AL = 'n' ?
             jne    Question                ; Non, repose la question
            ; CF = 0 (égalité), demande éventuellement au DOS de continuer
     
    Retour_int23:
            pop     dx                      ; Restitue les registres (pile LIFO :
            pop     ax                      ; Last Input, First Output)
            pop     bp
            jnc     Retour_DOS              ; Retour au traitement du DOS
            add     sp,6                    ; Nettoie l'adresse de retour du DOS
    Retour_DOS:
            iret                            ; Retour d'interruption
    Traiter_Ctrl_Break      EndP
    Ainsi, si l'utilisateur répond « n », le DOS retournera au programme là où il fut interrompu. Si l'utilisateur répond « o », l'adresse de retour au DOS est supprimée de la pile et l'adresse de retour au programme est modifiée pour que IRET se branche sur la fin du programme.

    En outre, si c'était une opération disque du DOS qui risquait d'être interrompue (chose permise par BREAK sur ON), mieux valait faire précéder STC par les lignes suivantes :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
            mov     ah,0Dh                  ; Vider tampons disque internes du DOS
            int     21h


    P.S. : j'espère que vous lirez un jour ce message.
    J'aurais répondu plus rapidement si vous aviez posé la question dans la bonne section. Pensez aussi à mettre un titre plus précis : traitement de l'interruption 23h, par exemple.

  3. #3
    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 Rectification de la routine INT23h
    En fait, RETF 2 doit être remplacé par RETF tout court pour que le bit de retenue soit étudié par MS-DOS 2 ou plus. C'est la présence du mot non retiré de la pile (registre FLAG lors d'INT23h) qui lui fera comprendre qu'IRET n'a pas été utilisé.
    Quant au RESET DISK (fct 0Dh du DOS), il est en fait conseillé de l'effectuer lorsqu'on ne compte pas revenir au DOS lors d'une INT23h mais de continuer dans le programme. En effet, DOS s'est mis dans un état critique (usage différent des piles internes) et seul l'usage d'une fonction DOS supérieure à 0Ch peut officiellement l'en faire sortir. Ainsi, la plupart des TSR usant du DOS ne seront plus en attente.

Discussions similaires

  1. [C#]Quel bibliothèque pour traiter le son en C#
    Par thomfort dans le forum Windows Forms
    Réponses: 5
    Dernier message: 08/06/2006, 02h46
  2. [XSLT]utiliser une feuille xsl pour traiter différents xml
    Par pistache42 dans le forum XSL/XSLT/XPATH
    Réponses: 4
    Dernier message: 09/05/2006, 19h19
  3. 2.pl lancé par 1.pl : pb pour traiter les erreurs
    Par kafifi dans le forum Langage
    Réponses: 8
    Dernier message: 18/11/2005, 01h07
  4. Réponses: 4
    Dernier message: 09/06/2005, 00h28
  5. [NASM] Redirection de l'interruption 09h
    Par sirozz dans le forum Assembleur
    Réponses: 2
    Dernier message: 16/07/2004, 18h32

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