2016-03-10 2 views
3

J'essaie de faire une extension du noyau xv6 pour mon cours Systèmes d'exploitation et je suis en train de tomber sur un bug étrange qui a pris 5 heures de mon temps en vain. J'ai implémenté un système de gestion de signal qui insère manuellement une fonction de gestion de signal et des arguments dans le pointeur d'instruction, et maintenant j'essaie de sauvegarder les valeurs de registre volatiles en les poussant sur la pile utilisateur, puis de les placer dans leur registre d'origine. résultats.La manipulation de cadres de pile en xv6 ne fonctionne correctement qu'avec un printf()?

Voici comment configurer le cadre de la pile:

void handle_signal(int signo, struct trapframe *tf){ 
     *((uint*)(tf->esp-4)) = tf->eip; 
     *((uint*)(tf->esp-8)) = proc->tf->eax; 
     *((uint*)(tf->esp-12)) = proc->tf->ecx; 
     *((uint*)(tf->esp-16)) = proc->tf->edx; 
     *((uint*)(tf->esp-20)) = signo; 
     *((uint*)(tf->esp-24)) =(uint)proc->pop; 
     tf->esp = tf->esp-24; 
     tf->eip = (uint)(proc->sigHandlers[signo]); 
    } 

Je suis la mise en bas de la pile à l'ancien pointeur d'instruction, poussant les registres volatils, poussant l'argument de gestionnaire de signal sur, pousser la fonction qui va faire apparaître les registres, et enfin régler eip (le pointeur d'instruction) égal à l'adresse du gestionnaire de signal.

void 
popregs(void){ 
    sleep(5); 

    __asm__ (
    "add $16, %esp;" 
    "pop %edx;" 
    "pop %ecx;" 
    "pop %eax;" 
    "ret"); 
} 

Voici la fonction que j'utilise pour faire apparaître les registres. Ce qui est vraiment étrange, c'est que mon programme va faire la bonne chose (enregistrer correctement la valeur des registres) si j'ai cette commande sleep (5) ou printf() juste avant l'assembly inline, mais si je l'enlève, je reçois une instruction "code hors limites" que je suppose être l'équivalent xv6 d'une erreur de segmentation. Même quand il enregistre correctement les valeurs des registres, je peux dire que la pile est en train de se foirer parce que les gestionnaires échouent sur les appels de traitement de signal plus tard.

J'ai du mal à faire face à cela car je ne sais pas vraiment comment bien déboguer l'assemblage - est-ce que quelqu'un a une idée de ce qui pourrait se passer?

+0

Pourquoi ajouter 16 octets? – immibis

Répondre

4

Lors de l'entrée d'une procédure (comme popregs), le compilateur définit normalement une pile en modifiant esp. Donc, si le add $16,%esp est correct, cela dépend du fait, si le compilateur soustrait 8 de esp ou pas. Si vous supprimez sleep (5), le compilateur n'a probablement pas généré de code pour modifier esp car la procédure est une procédure feuille donc vous avez besoin d'un add $8,%esp à la place.

+0

Wow, comment diable n'ai-je pas ramassé plus tôt? J'aurais pu jurer que je l'ai déjà fait ... merci beaucoup – hendersawn

+3

@hendersawn Toute fonction qui repose sur la disposition exacte de la pile, vous devriez probablement écrire dans l'assemblage. Cela signifie 'popregs' et les gestionnaires de signaux eux-mêmes. – immibis