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 :

Probleme gestion d'interruptions


Sujet :

x86 32-bits / 64-bits Assembleur

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

    Informations forums :
    Inscription : Novembre 2011
    Messages : 14
    Points : 5
    Points
    5
    Par défaut Probleme gestion d'interruptions
    Bonjour,

    Je suis actuellement en train de developper un micro-kernel en x86 et je bute sur un point. En effet, j'essaye de gérer les exceptions ( exemple : division par 0 ) mais je n'arrive pas à passer outre.

    Je m'explique, je crée une fonction qui effectue une division par 0 :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    int divide_zero_test()
    {
      int x = 3;
      int y = 0;
      int z = 51;
      printf("Ca rentre \n");
      z = x / y;
      printf("Ca sort \n"); 
      return z;
    }
    Celle ci entraine l'execution du fonction assembleur qui push l'exception sur la stack, puis d'un context save qui sauve tout les parametres et appele ma gestion d'exception :

    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
     
    isr_0:
    	cli
    	push $0
    	jmp ctxt_save
     
    ctxt_save:
    	mov (%esp), %eax
    	pusha	
    	pushf
    	push %eax
     
    	call arch_handler
    	pop %eax	
     
    	popf
    	popa
    	add $4, %esp
    	sti
      	iret
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    void		arch_handler(t_uint32 id)
    {
      if (id == 0)
        {
          printf("Divide error\n");
          return;
        }
    Mon probleme est que, si je declenche l'interruption par du code asm : asm volatile ("int $0"); cela marche parfaitement mais lors que je declenche l'exception par la fonction divide_per_zero, le message d'erreure apparait comme une boucle infinie.

    Il m'est apparu grace a gdb et la commande disass, que le registre esp pointait ( a la fin de la fonction ctxt_save sur la ligne assembleur effectuant la division et non pas sur l'instruction suivante ! Cela creant donc une exception a l'infinie.

    Ma question est donc, comment sortir de cette "boucle" infinie ? Et pourquoi ce code marche lors d'une exception lancée "en dur" et pas lors du declenchement par une fonction C?

    En esperant avoir été claire, je vous remercie d'avance pour vos réponses et vous souhaite une bonne soirée

  2. #2
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 400
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 400
    Points : 23 785
    Points
    23 785
    Par défaut
    Hello,

    Il m'est apparu grace a gdb et la commande disass, que le registre esp pointait ( a la fin de la fonction ctxt_save sur la ligne assembleur effectuant la division et non pas sur l'instruction suivante ! Cela creant donc une exception a l'infinie.

    Ma question est donc, comment sortir de cette "boucle" infinie ? Et pourquoi ce code marche lors d'une exception lancée "en dur" et pas lors du declenchement par une fonction C?
    La réponse est dans le manuel des architectures IA-32 et 64 :

    Citation Envoyé par Intel® 64 and IA-32 Architectures Developer's Manual

    6.5 EXCEPTION CLASSIFICATIONS

    Exceptions are classified as faults, traps, or aborts depending on the way they are reported and whether the instruction that caused the exception can be restarted without loss of program or task continuity.

    Faults — A fault is an exception that can generally be corrected and that, once corrected, allows the program to be restarted with no loss of continuity. When a fault is reported, the processor restores the machine state to the state prior to the beginning of execution of the faulting instruction. The return address (saved contents of the CS and EIP registers) for the fault handler points to the faulting instruction, rather than to the instruction following the faulting instruction.

    Donc, ton micro-processeur distingue les cas d'interruptions et d'exception et si cette dernière peut être rattrapée, alors il se repositionne sur l'instruction fautive pour la ré-exécuter une fois le handler appelé, car ce dernier est censé avoir corrigé la cause de l'erreur. C'est utile, par exemple, si tu utilises la mémoire virtuelle et qu'une page n'est pas encore chargée en mémoire.

    Une division par zéro est théoriquement rattrapable dans le sens où soit elle a été compilée comme ça à la base et, dans ce cas, c'est le rôle du compilo de te prévenir, soit c'est parce que tu utilises un registre chargé au préalable et, dans ce cas, on peut très bien rectifier les pré-conditions et reprendre ensuite le processus où on en était.

    Quand tu fais « INT 0 », par contre, tu indiques clairement au processeur que c'est une « interruption logicielle », qui plus est demandée explicitement par le programmeur, et pas une exception. Dans ce cas, le CPU se positionne juste après l'instruction, même si le vecteur suivi est le 00h.

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

    Informations forums :
    Inscription : Novembre 2011
    Messages : 14
    Points : 5
    Points
    5
    Par défaut
    Merci beaucoup de ta réponse !

    Si j'ai bien compris, dans ma fonction arch_handler, je ne peux pas me contenter de faire un printf mais je dois régler la cause de l'interruption?

    Donc dans le cas d'une division par 0, dans ma fonction division_par_zero, celle si est effectuée par idivl -0x10(%ebp), la valeur contenue dans -0x10(%ebp) est donc le divisieur à en croire la doc intel. Comment modifier cette valeur? Sachant que pour mon binome, la division est effectuée a -0x08(%ebp)....
    Il me semble que cela depend ou sont stockés les variables locales définies dans la fonction C donc comment faire un traitement "générique" à cela?

    De plus, ne faudrait il pas, en plus de traiter l'interruption, lui signaler que l'interruption à été réglée? Si oui, comment faire cela?

    Merci de ta patience

  4. #4
    Membre confirmé Avatar de bifur
    passe le balais et l'aspirateur
    Inscrit en
    Mars 2008
    Messages
    314
    Détails du profil
    Informations personnelles :
    Âge : 39

    Informations professionnelles :
    Activité : passe le balais et l'aspirateur

    Informations forums :
    Inscription : Mars 2008
    Messages : 314
    Points : 550
    Points
    550
    Par défaut
    je te conseillerait plutot de faire un gestionnaire d'exception qui arrete le programme qui a déclenché l'exception et de faire des programme qui gère la possibilité de diviser avec 0 , par exemple:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    if (z != 0){
    z = x / y;
    }else{
    z = "+infinis";
    }
    si tu souhaite quand même tenter de corriger l'erreur il te faudras:
    1 récuperer l'adresse empile lors du declenchement de l'erreur
    2 décoder l'instruction qui a déclenché l'erreur pour determiner si on a affaire a div ou idiv, en 8, 16 ou 32bit (pour deterniner ça il te faudrat aussi savoir si le segment du programme effectuait du code en 16 ou 32bit)
    3 modifier les registres eax et edx (les sortie d'une instruction div ou idiv) suivant la taille des registres uttilisé par celle ci avec des valeur illustrant un nombre infinis (en général un truc du genre 0FFFFh)
    4 definir l'adresse de retour et sauter a celle ci (en ayant bien restauré tous les registre et flag modifié par la routine d'exception)


    ou alors:
    3' modifier le registre diviseur pour qu'il ne fasse plus zéros
    4' iret, la division ne seras plus par zéros

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

    Informations forums :
    Inscription : Novembre 2011
    Messages : 14
    Points : 5
    Points
    5
    Par défaut
    Merci également pour ta réponse !

    je te conseillerait plutot de faire un gestionnaire d'exception qui arrete le programme qui a déclenché l'exception et de faire des programme qui gère la possibilité de diviser avec 0 , par exemple:
    En fait je ne peux pas procéder comme cela car c'est un projet pour mon école et les tests seront fait par des programmes declenchant les différentes exceptions possibles...

    ou alors:
    3' modifier le registre diviseur pour qu'il ne fasse plus zéros
    4' iret, la division ne seras plus par zéros
    Mon probleme est bien la, quand une division est effectuée, le idiv est appelé avec le divisieur qui est lui meme une variable définie en C.

    Sachant que pour ce code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    int func()
    {
     int x = 3;
     int y = 0;
     int z;
     
     z = x / y;
     return z;
    }
    On se retrouve donc avec un truc du genre :
    mov 0x3, -0xc(%ebp)
    mov 0x0, -0x10(%ebp)
    ....
    IDIV -0x10(%ebp) ( sachant que c'est modulo le nombre de variables définies precedamment.... )

    Je but sur ce point, comment modifier la valeur de -0x10(%ebp) afin de lui mettre une valeur > 0 pour pouvoir enlever la division par 0 lors de la "deuxieme" execution? Sachant egalement que cette endroit n'est pas fixe en mémoire qu'il depend du nombre de variables définies, des differentes fonctions présentes dans la stack...

    Merci

  6. #6
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 400
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 400
    Points : 23 785
    Points
    23 785
    Par défaut
    Si j'ai bien compris, dans ma fonction arch_handler, je ne peux pas me contenter de faire un printf mais je dois régler la cause de l'interruption?
    Non. C'est vrai en soi, mais ce n'est pas ce que j'ai essayé de montrer.

    Ce que je veux dire, c'est que ton processeur va distinguer les « interruptions » des « exceptions ». Et le paragraphe que j'ai cité indique que dans le second cas, l'adresse de retour est celle de l'instruction fautive, justement pour pouvoir la reprendre.

    C'est pourquoi tu rentres en boucle infinie quand tu provoques une vraie division par zéro alors que le programme reprend son cours normalement lorsque tu appelles « INT 00h ».

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

    Informations forums :
    Inscription : Novembre 2011
    Messages : 14
    Points : 5
    Points
    5
    Par défaut
    Oui, ca je l'avais compris grace a ton post précédent mais mon probleme maintenant est de resoudre l'exception en tant que t'elle d'ou mon dernier post ou j'explique que le idiv prend le diviseur sur la stack et que je ne comprends pas comment le modifier pour resoudre la division par 0 lors du "second" passage par celle ci

  8. #8
    Membre confirmé Avatar de bifur
    passe le balais et l'aspirateur
    Inscrit en
    Mars 2008
    Messages
    314
    Détails du profil
    Informations personnelles :
    Âge : 39

    Informations professionnelles :
    Activité : passe le balais et l'aspirateur

    Informations forums :
    Inscription : Mars 2008
    Messages : 314
    Points : 550
    Points
    550
    Par défaut
    pour determiner quel est l'adresse de ta variable il va te falloir décoder les instruction compilé (les opcodes) de l'instruction fautive, c'est la que tu trouveras l'adressse de la variable

    tu trouveras plein d'info pour ça dans le "Intel Architecture Software Developer’s Manual Volume 2: Instruction Set Reference"
    en particulier dans les parties "INSTRUCTION FORMATS AND ENCODINGS" et "ADDRESSING-MODE ENCODING OF MODR/M AND SIB
    BYTES"

    ça a l'air sympa ton école au vu du boulot qu'ils vous font faire c'est laquelle?

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

    Informations forums :
    Inscription : Novembre 2011
    Messages : 14
    Points : 5
    Points
    5
    Par défaut
    Merci je vais aller voir ca!

  10. #10
    Futur Membre du Club
    Profil pro
    Inscrit en
    Novembre 2011
    Messages
    14
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2011
    Messages : 14
    Points : 5
    Points
    5
    Par défaut
    A la lecture de ce chapitre, je pense que cela me parait enorme comme travail pour une interruption ( sachant que l'on doit gérer les 31 exceptions présentes dans l'architecture x86... )

    N'y a t il pas moyen de "contourner" l'exception? Je m'explique, j'aimerais lui dire :
    "Tu es passé par une exception, je l'ai identifié et traité à ma manière, lors de ton second passage, l'interruption a bien été traitée, passe à l'instruction suivante."

    En gros, j'aimerais coder une sorte d'End of Interrupt mais je ne sais pas comment m'y prendre...

    Merci en tout cas pour votre patience

  11. #11
    Membre confirmé Avatar de bifur
    passe le balais et l'aspirateur
    Inscrit en
    Mars 2008
    Messages
    314
    Détails du profil
    Informations personnelles :
    Âge : 39

    Informations professionnelles :
    Activité : passe le balais et l'aspirateur

    Informations forums :
    Inscription : Mars 2008
    Messages : 314
    Points : 550
    Points
    550
    Par défaut
    je serait toi j'essayerai plutot de sauter la division fautive car je pense qu'un kernel qui modifie les variable d'un programme crée de l'instabilité dans celui ci, car la variable en question n'est peut etre pas qu'uttilisé par la division

    un kernel qui modifie quoi que ce soit dans un de ses prog (variable ou résultat d'une opération) me semble être une idée vraiment tordu. j'espère que l'exercice n'as pas dans l'idée de vous inciter a le faire dans vos prochaine créations

    et moi je vais dormir car je ne suis pas un vrai informaticien qui code toute la nuit

    edit: chaque exception est différente et doit être traité de façon différente, la division par zéros est une erreur qui doit a mon avis déclencher l'arrêt du programme qui en est a l'origine (tout comme l'erreur de protection général par exemple)
    peut être faudrait il alors commencer par bien voir comment se comportent les différentes exception car certaines n'ont besoin en réalité de ne pointer que sur un iret

  12. #12
    Futur Membre du Club
    Profil pro
    Inscrit en
    Novembre 2011
    Messages
    14
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2011
    Messages : 14
    Points : 5
    Points
    5
    Par défaut
    C'est vrai que je me rends compte que l'idée de modifier les variables n'est vraiment pas bonne :/

    L'exercice n'a pas ce but mais je debute dans la programmation kernel et j'essaye de m'en sortir avec les idées qui me passent par la tete ( et comme je tourne en rond, j'ai des idées saugrenues ^^ )

    je serait toi j'essayerai plutot de sauter la division fautive
    C'est exactement ce que j'essaye de faire mais je ne vois pas comment m'y prendre car je dois passer par l'exception pour pouvoir la reconnaitre et faire mes traitement ( isr, sauvegarde du contexte... )

    Il faudrait que je puisse la sauter dans un deuxieme temps ( lors du contexte save? ) mais comment? On ne peut pas modifier la valeur de l'eip ...

    En tout cas, je te souhaite une bonne nuit

  13. #13
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 400
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 400
    Points : 23 785
    Points
    23 785
    Par défaut
    L'idée est de résoudre le problème en amont, c'est-à-dire choisir la bonne politique. Lors d'une interruption logicielle, le micro-processeur considère (à juste titre) qu'il exécute ton instruction puisque tu te retrouves dans la bonne procédure. Dans le cas d'une exception, tu te retrouves dans la même procédure parce que le micro-processeur ne peut pas exécuter ton instruction.

    Donc, « passer » cette instruction pour simuler le comportement de INT n'a pas vraiment de sens car il s'agit en fait d'un choix de traitement comme un autre. Dans tous les cas, ce n'est pas le déroulement exact du programme. Passer une instruction qui a en principe vocation a être exécutée a toutes les chances de provoquer une cascade de bugs en aval.

    Le mieux consiste à mettre fin au programme avec un message explicite, comme le font tous les systèmes d'exploitation, à moins que tu aies des consignes particulières pour ton projet.

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

    Informations forums :
    Inscription : Novembre 2011
    Messages : 14
    Points : 5
    Points
    5
    Par défaut
    Merci pour cette reponse claire !

    Je n'ai pas vraiment de consignes a ce sujet, mais je pense que le micro kernel doit finir son "lancement" car il y a des opérations effectuées après les tests...

    Mais si je pars sur l'idée d'interrompre le programme, je me demande comment l'arreter "proprement", je m'explique j'ai entre autre :

    Mon isr :
    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
    isr_0:
    	cli
    	push $0
    	jmp ctxt_save
     
    ctxt_save:
    	mov (%esp), %eax
    	pusha	
    	pushf
    	push %eax
     
    	call arch_handler
    	pop %eax	
     
    	popf
    	popa
    	add $4, %esp
    	sti
      	iret
    et mon handler :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    void		arch_handler(t_uint32 id)
    {
      if (id == 0)
        {
          printf("Divide error\n");
          return;
        }
    Si je mets un 'asm volatile ("hlt"); dans ma arch_handler, celle ci va interrompre le prog et donc le context save ne sera pas applique correctement. ( remettre la stack en ordre, remettre les flags... )
    Autre solution si je met un "hlt" avant mon iret dans la context save, les flags ne seront pas mis a jour non plus....

    Comment faire une mise en pause "propre" dans ce cas?

    Désolé de vous embeter avec toutes ces questions mais je dois vous avouer que je nage un peu avec ce probleme ^^'

  15. #15
    Membre confirmé Avatar de bifur
    passe le balais et l'aspirateur
    Inscrit en
    Mars 2008
    Messages
    314
    Détails du profil
    Informations personnelles :
    Âge : 39

    Informations professionnelles :
    Activité : passe le balais et l'aspirateur

    Informations forums :
    Inscription : Mars 2008
    Messages : 314
    Points : 550
    Points
    550
    Par défaut
    pourrait tu nous expliquer le but de ton kernel?

    si il s'agit d'un microkernel qui déclenche toutes les exception pour pouvoir les tester je te conseille de mettre un bit correspondant a une exception a 1 lors du déclenchement de celle ci et de redemarrer ton programme et dans ton programme tu sauteras toute les test das exception dont le bit auras été mis a 1

    pour faire une pause propre j'uttilisse en général:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    bouclepause:
    hlt
    ;ici comparaison pour avoir la condition d'arret de la pause
    jne bouclepause
    l'instruction hlt stoppe le fonctionnement processeur jusqu'a la prochaine IRQ

  16. #16
    Futur Membre du Club
    Profil pro
    Inscrit en
    Novembre 2011
    Messages
    14
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2011
    Messages : 14
    Points : 5
    Points
    5
    Par défaut
    Désolé de cette réponse si tardive mais j'ai eu une coupure du net -.-

    Merci pour ta solution, je vais essayé de l'adapter à mon code.

    Le but de mon micro kernel est de respecter le manuel intel IA32 Software Developer's manual Volume 3A : System Programming Guide et en l'occurence pour cette tranche, le chapitre 6 concernant les interruptions / exceptions

Discussions similaires

  1. probleme gestion condition switch - case
    Par DarkMax dans le forum Langage
    Réponses: 5
    Dernier message: 07/09/2005, 14h25
  2. Gestion des interruptions du µProcesseur
    Par herve13 dans le forum Assembleur
    Réponses: 3
    Dernier message: 22/08/2005, 20h51
  3. Gestion des interruptions du microprocesseur sous XP
    Par herve13 dans le forum API, COM et SDKs
    Réponses: 4
    Dernier message: 20/08/2005, 18h29
  4. Réponses: 7
    Dernier message: 02/03/2005, 14h45
  5. Probleme gestion camera
    Par Fry dans le forum DirectX
    Réponses: 3
    Dernier message: 03/12/2004, 11h41

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