2010-05-13 10 views
4

J'ai une fonction C à un seul trait qui est juste return value * pow(1.+rate, -delay); - elle actualise une future valeur à une valeur actuelle. La partie intéressante du démontage estPourquoi FLD1 charge-t-il NaN à la place?

 
0x080555b9 :  neg %eax 
0x080555bb :  push %eax 
0x080555bc :  fildl (%esp) 
0x080555bf :  lea 0x4(%esp),%esp 
0x080555c3 :  fldl 0xfffffff0(%ebp) 
0x080555c6 :  fld1 
0x080555c8 :  faddp %st,%st(1) 
0x080555ca :  fxch %st(1) 
0x080555cc :  fstpl 0x8(%esp) 
0x080555d0 :  fstpl (%esp) 
0x080555d3 :  call 0x8051ce0 
0x080555d8 :  fmull 0xfffffff8(%ebp) 

Bien que simple pas à pas dans cette fonction, gdb dit (taux est de 0,02, le retard est 2, vous pouvez les voir sur la pile):

 

(gdb) si 
0x080555c6  30  return value * pow(1.+rate, -delay); 
(gdb) info float 
    R7: Valid 0x4004a6c28f5c28f5c000 +41.68999999999999773  
    R6: Valid 0x4004e15c28f5c28f6000 +56.34000000000000341  
    R5: Valid 0x4004dceb851eb851e800 +55.22999999999999687  
    R4: Valid 0xc0008000000000000000 -2       
=>R3: Valid 0x3ff9a3d70a3d70a3d800 +0.02000000000000000042  
    R2: Valid 0x4004ff147ae147ae1800 +63.77000000000000313  
    R1: Valid 0x4004e17ae147ae147800 +56.36999999999999744  
    R0: Valid 0x4004efb851eb851eb800 +59.92999999999999972  

Status Word:   0x1861 IE    PE  SF    
         TOP: 3 
Control Word:  0x037f IM DM ZM OM UM PM 
         PC: Extended Precision (64-bits) 
         RC: Round to nearest 
Tag Word:   0x0000 
Instruction Pointer: 0x73:0x080555c3 
Operand Pointer:  0x7b:0xbff41d78 
Opcode:    0xdd45 

Et après la fld1:

 
(gdb) si 
0x080555c8  30  return value * pow(1.+rate, -delay); 
(gdb) info float 
    R7: Valid 0x4004a6c28f5c28f5c000 +41.68999999999999773  
    R6: Valid 0x4004e15c28f5c28f6000 +56.34000000000000341  
    R5: Valid 0x4004dceb851eb851e800 +55.22999999999999687  
    R4: Valid 0xc0008000000000000000 -2       
    R3: Valid 0x3ff9a3d70a3d70a3d800 +0.02000000000000000042  
=>R2: Special 0xffffc000000000000000 Real Indefinite (QNaN) 
    R1: Valid 0x4004e17ae147ae147800 +56.36999999999999744  
    R0: Valid 0x4004efb851eb851eb800 +59.92999999999999972  

Status Word:   0x1261 IE    PE  SF  C1  
         TOP: 2 
Control Word:  0x037f IM DM ZM OM UM PM 
         PC: Extended Precision (64-bits) 
         RC: Round to nearest 
Tag Word:   0x0020 
Instruction Pointer: 0x73:0x080555c6 
Operand Pointer:  0x7b:0xbff41d78 
Opcode:    0xd9e8 

après cela, tout va en enfer. Les choses deviennent grossièrement ou sous-évaluées, donc même s'il n'y avait pas d'autres bugs dans ma tentative d'IA freeciv, il choisirait toutes les mauvaises stratégies. Comme envoyer toute l'armée dans l'Arctique. (Soupir, si seulement je devais aller aussi loin.)

Je dois manquer quelque chose d'évident, ou être aveuglé par quelque chose, parce que je ne peux pas croire que fld1 devrait jamais échouer. Encore moins qu'il ne devrait échouer qu'après une poignée de passes à travers cette fonction. Lors des passes précédentes, la FPU charge correctement 1 dans ST (0). Les octets à 0x080555c6 codent définitivement fld1 - vérifié avec x/... sur le processus en cours d'exécution.

Ce qui donne?

Répondre

6

Remarquablement approprié. Ce que vous avez ici est un débordement de pile. Plus précisément, vous (ou éventuellement votre compilateur) avez débordé la pile x87. Il ne peut contenir que 8 valeurs, et au moment où le fld1 est émis, il est déjà plein (indiqué par le mot-clé 0000). Ainsi, le fld1 déborde de la pile (indiqué par IE, SF, C1) ce qui provoque le résultat que vous voyez. Pour savoir pourquoi cela se produit, vous pouvez avoir utilisé les instructions MMX sans utiliser un EMMS avant d'utiliser les instructions x87, ou votre compilateur a un bug, ou vous avez un code d'assemblage quelque part qui viole l'ABI de votre plateforme (ou une bibliothèque vous utilisez enfreint l'ABI).

+1

Ah, vous les gars rock! Merci! Cela me conduisait au mur. Quant à savoir pourquoi cela se produit: probablement parce que j'avais déplacé une fonction en appelant une autre qui renvoie 'double' d'un fichier à l'autre, et dans le nouveau fichier, il n'y avait pas de prototype pour la fonction à virgule flottante. la valeur de retour de la pile. Je m'attendais à être à court de pile FP beaucoup plus tôt cependant, mais maintenant il semble fonctionner beaucoup mieux maintenant que j'ai fourni un prototype. Maintenant, je peux passer à la prochaine erreur de segmentation! –

+0

@Bernd: Oui, cela peut certainement causer ce genre de problème. –

4

Il semble que vous ayez un débordement de pile FPU. Le mot d'étiquette FPU est 0, ce qui signifie que tous les registres sont utilisés. Vous pouvez également voir tous les registres marqués comme "valides", alors que je m'attendrais à ce que certains soient vides.

Je ne sais pas pourquoi cela se passerait bien. Peut-être avez-vous du code MMX qui n'émet pas l'instruction EMMS? Ou peut-être un assemblage en ligne qui n'efface pas la pile correctement?

Questions connexes