[Kos-dev] Comportement étrange ...

Thomas Petazzoni thomas.petazzoni at enix.org
Wed Sep 29 20:18:51 CEST 2004


Salut,

On Wed, Sep 29, 2004 at 12:35:19AM +0200, Thomas Petazzoni wrote :

> J'ai un comportement assez étrange dans Bochs lors du partage de
> pages. Si ça se trouve, je me plante complètement, je ne sais
> pas. Enfin voilà ce qui se passe :

J'ai trouvé la raison du problème : notre compère gcc. Il se la joue
un peu trop genre "moa j'suis trop baleze, j'optimise ton code à fond
les manettes" !

Voilà l'explication :

 1) Si on prend le code C suivant :

   1. data = (unsigned *) va2;
   2. data[123] = 0xDEADBEEF;
   3. data = (unsigned *) va3;
   4. Lecture de la donnée data[123] pour affichage

   Alors gcc me génère le code suivant :

   2a8:   a1 ec 21 00 04          mov    0x40021ec,%eax
   2ad:   ba ef be ad de          mov    $0xdeadbeef,%edx
   2b2:   89 15 ec 11 00 04       mov    %edx,0x40011ec

   Il commence par charger ce qu'il y a à (va3 + 123) dans eax, puis
   charge edx avec 0xDEADBEEF, et mets cette valeur à (va2 +
   123). Sympa le gars ;-)

 2) L'ajout de la boucle suivante entre l'écriture et la lecture ne
    change rien :

    {
      int j;
      for (j = 0; j < 2; j++) { j++; j--; }
    }

    En effet, gcc considère que pour 2 itérations, cette boucle est
    inutile.

    A noter que pour 3 itérations, gcc considère que ça vaut le coup
    de laisser le code faire quelque chose, et donc il y a du code
    entre l'écriture et la lecture, et celles-ci sont dans le bon
    ordre.

 3) L'ajout d'un asm("nop") entre l'écriture et la lecture entraîne la
    génération du code suivant :

    2a8:   ba ef be ad de          mov    $0xdeadbeef,%edx
    2ad:   89 15 ec 11 00 04       mov    %edx,0x40011ec
    2b3:   90                      nop
    2b4:   a1 ec 21 00 04          mov    0x40021ec,%eax

    Là, tout est bon, il fait bien les choses dans le bon ordre.

 4) Si je mets ce code dans la fonction kernel_start(), alors gcc
    génère le code suivant :

    44c:   b8 ef be ad de          mov    $0xdeadbeef,%eax
    451:   a3 ec 11 00 04          mov    %eax,0x40011ec
    456:   a1 ec 21 00 04          mov    0x40021ec,%eax

    Le 0xDEADBEEF est bien écrit sur la page va2 avant d'être lu via
    la page va3.

Voilà, donc on retombe bien sur ses pieds. Je me demande dans quelle
mesure ce genre d'optimisations peut jouer des tours au
programmeur. Un problème connu avec ces optimisations est le dialogue
avec des contrôleurs ou autres éléments matériels : si ils requièrent
d'écrire d'abord dans tel registre puis dans tel autre, alors ce genre
d'optimisations peut être ennuyeuse. D'après ce que j'ai compris, la
solution Linux s'appelle les "memory barriers". Par exemple, en
appelant wmb(), on s'assure que toutes les écritures en attente vont
être effectuées avant d'éxécuter les instructions qui suivent.

Bonne soirée !

Thomas
-- 
PETAZZONI Thomas - thomas.petazzoni at enix.org 
http://thomas.enix.org - Jabber: kos_tom at sourcecode.de
KOS: http://kos.enix.org/ - Lolut: http://lolut.utbm.info
Fingerprint : 0BE1 4CF3 CEA4 AC9D CC6E  1624 F653 CB30 98D3 F7A7


More information about the Kos-dev mailing list