[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