Bonjour,
Je dev un OS (à titre perso) avec sa libc associée et je viens de résoudre un bug qui affectait bochs mais pas qemu :
En gros, mon application userspace reconfigure le tty pour le passer en raw (copie de la conf courante, passage en raw, application de la nouvelle conf). J'ai donc écrit pour recopier la conf courante : struct termios newt = oldt;
avec oldt un struct termios déclaré juste au dessus et initialisé comme il faut par un syscall.
C'est précisément cette ligne qui me fait planter mon OS sous bochs mais qui marche parfaitement sous QEMU. Alors par curiosité j'ai remplacé par un memcpy(&newt, &oldt, sizeof(newt)) et là, ô miracle, ça marche.
Est-ce que quelqu'un pourrait m'expliquer la différence fondamentale entre ces 2 solutions ? Et pourquoi ça marcherait avec un émulateur et pas un autre.
Merci.
Mise à jour du 26/01/2015 :
Le problème était lié à la valeur du registre « es » que j'avais mal initialisé. QEMU aurait dû me lever une exception (GPE) comme le fait Bochs mais il est visiblement assez permissif.
# Type de compilation ?
Posté par Obsidian . Évalué à 1.
Est-ce que tu programmes en C pur ou en C++ ? D'une manière générale, même si c'est autorisé depuis C99, c'est toujours une mauvaise idée de déclarer une nouvelle variable au milieu d'une procédure.
D'autre part, il se peut également que ça fonctionne « par accident ».
Tu peux nous montrer ton code ?
[^] # Re: Type de compilation ?
Posté par Maxime (site web personnel) . Évalué à 2.
C'est du C99.
[^] # Re: Type de compilation ?
Posté par reno . Évalué à 2.
Pour autant que je sache, la seule différence entre une affectation de structure et un memcpy est que memcpy initialise aussi les octets de padding/rembourrage, ce qui a priori n'a pas d'impact.
Donc plusieurs hypothèses:
1) tu t'es trompé et le problème ne vient pas de là
2) la différence sur les octets de bourrage ont un impact sur l'émulateur (??)
3) bug du compilateur: essayer de regarder l'assembleur généré.
[^] # Re: Type de compilation ?
Posté par Maxime (site web personnel) . Évalué à 2.
J'ai eu ce problème aussi avec une autre application qui cherchait à faire un truc similaire et remplacer newt = oldt; par un memcpy a aussi résolu le bug. Si je ne me trompe pas de bug, sur cette application, l'exception levée était un General Protection Fault (GDT:0x00000000) et j'avais le bug avec bochs, kvm et virtualbox.
Mais sinon, je veux bien croire à un effet de bord, c'est justement la raison pour laquelle je pose la question au lieu de me dire que le problème est réglé. Mais je ne vois pas trop… J'essaierai de faire d'autres tests ce soir pour voir si le problème se pose avec toutes les structures, si les syscall qui précèdent ont une importance, etc.
wtf :).
Ouais, j'y ai songé, mais ce qui m'étonne c'est que justement ça varie d'un émulateur à l'autre (et compilé avec glibc puis exécuté sous Linux, je n'ai aucun problème non plus).
[^] # Re: Type de compilation ?
Posté par Maxime (site web personnel) . Évalué à 3.
Voici un code minimaliste qui fait planter sous Bochs :
[^] # Re: Type de compilation ?
Posté par Maxime (site web personnel) . Évalué à 2.
J'ai donc compilé avec ma libc une fonction qui contient le code ci-dessus.
Code qui plante :
code qui ne plante pas :
Est-ce que quelqu'un qui parle l'assembleur x86 couramment pourrait en faire un petit commentaire ?
[^] # Re: Type de compilation ?
Posté par Kerro . Évalué à 2.
Dans ton premier extrait de code il y a trois push et quatre pop, d'où problème. Mais il est probable que ton extrait ne soit pas complet à ce sujet, sinon les deux émulateurs planteraient.
[^] # Re: Type de compilation ?
Posté par Maxime (site web personnel) . Évalué à 3.
Je pense que mon extrait est assez complet, voici un diff pour compléter :
Qu'est-ce qui pourrait être à l'origine de ce problème ? D'ailleurs, j'ai remplacé la structure termios par :
struct toto {
int c[17];
};
Et j'ai le bug pour une valeur >= 17. En dessous, il ne fait pas de push/pop mais plein de movl.
[^] # Re: Type de compilation ?
Posté par Maxime (site web personnel) . Évalué à 3.
En fait, mon extrait était bien incomplet, le pushl %ebp est juste au dessus, commun aux 2 codes :
[^] # Re: Type de compilation ?
Posté par Maxime (site web personnel) . Évalué à 3.
Après avoir fait du pas à pas avec le debugguer de bochs, voici des infos complémentaires :
(0).[6946995606] [0x0000000002669023] 001b:40000023 (unk. ctxt): rep movsd dword ptr es:[edi], dword ptr ds:[esi] ; f3a5
CPU 0: Exception 0x0d - (#GP) general protection fault occured (error_code=0x0000)
CPU 0: Interrupt 0x0d occured (error_code=0x0000)
[^] # Re: Type de compilation ?
Posté par TheBreton . Évalué à 2.
Voir le code commenté si dessous, je pense que si ta pile à l'entrée de ta fonction est bien alignée sur 4 octets cela marche, sinon cela provoque le bug (l'instruction movsl requiert un alignement 32 bits pour les adresses source/destination).
[^] # Re: Type de compilation ?
Posté par Maxime (site web personnel) . Évalué à 2.
C'est une excellente remarque, peut-être que qemu n'est pas aussi regardant sur les problèmes d'alignement. Ce qui m'étonne c'est que j'ai tout un tas d'autres applications et que je n'ai jamais rencontré ce problème avant.
Ce soir, je jouerai un peu avec la pile pour voir. C'est vrai qu'on y place un tas d'infos (argc, argv, envp) sans se soucier de grand chose en terme d'alignement… Cette partie ne m'est pas entièrement familière car elle a été codée par un pote.
[^] # Re: Type de compilation ?
Posté par TheBreton . Évalué à 2.
Regarder aussi l'etat du bit de direction dans le registre EFLAGS
normalement on place une instruction cld ou std AVANT le "rep movsl"
suffit qu'il soit par defaut a 1 et le rep movsl compte dans la mauvaise direction donc illegal acces.
Je sait que sous linux (en tout cas dans le kernel) cela a causé des soucis avec gcc sup a 4.3 plus de detail la http://em386.blogspot.fr/2008/03/cldstd-and-gcc-430.html
[^] # Re: Type de compilation ?
Posté par Maxime (site web personnel) . Évalué à 2.
Merci pour le lien, je regarderai ça plus tard. J'ai testé vite fait l'affichage des adresses des variables a et b :
Et là, j'obtiens bien des adresses multiples de 4… Et ça plante après les printf.
[^] # Re: Type de compilation ?
Posté par TheBreton . Évalué à 1.
Tu peut compiler et essayer en rajoutant l'option -mcld à gcc ?
[^] # Re: Type de compilation ?
Posté par Maxime (site web personnel) . Évalué à 2.
Je viens d'essayer mais visiblement, ça ne change rien au code assembleur généré.
Du coup j'ai essayé d'afficher l'eflag et même de le modifier et : il est bien à 0 (vérifié depuis bochs mais aussi en rajoutant du code assembleur dans le code de test) et si je le change de sens, ça plante aussi.
(bon cela dit, effectivement, on s'en est pas soucié non plus il me semble donc ça aurait pu être une source de problème similaire à linux)
[^] # Re: Type de compilation ?
Posté par TheBreton . Évalué à 3.
ATTENTION je fais ca de mémoire ca remonte a loin le temps ou je codais en asm x86
donc il peut y avoir des erreurs de ma part
Code qui plante
Code qui plante pas
[^] # Re: Type de compilation ?
Posté par calandoa . Évalué à 6.
« D'une manière générale, même si c'est autorisé depuis C99, c'est toujours une mauvaise idée de déclarer une nouvelle variable au milieu d'une procédure. »
Pas d'accord! C'est toujours une bonne idée de ne déclarer une variable que lorsqu'on en a besoin afin qu'elle ai la plus faible portée (scope) possible. Ça facilite la compréhension et l'optimisation.
[^] # Re: Type de compilation ?
Posté par Obsidian . Évalué à 2.
C'est ce que je pense aussi mais je les ramène quand même en début du bloc le plus proche.
[^] # Re: Type de compilation ?
Posté par Krunch (site web personnel) . Évalué à 3.
Sauf que si tu as une fonction qui n'utilise certaines variables qu'à partir de la ligne 20, tu aurais sans doute mieux fait de la diviser en plus petites fonctions.
pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.
# Alignement?
Posté par calandoa . Évalué à 4.
Peut être une erreur d'alignement? Ta plateforme ne supporte pas les writes en 32bits non alignés, et le compilateur pense que si? Bon je dis ça, mais apparemment tu es sous x86 et la structure contient des int donc devrait être alignée.
[^] # Re: Alignement?
Posté par Maxime (site web personnel) . Évalué à 3.
Oui, cela serait étrange… Surtout que ça plante aussi avec
Mais peut-être l'utilisation d'une instruction non supportée par la plateforme émulée par Bochs ?
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.