2010-05-13 4 views
4

У меня есть функция с одним слоем C, которая равна return value * pow(1.+rate, -delay); - она ​​дает скидку на будущую стоимость текущей стоимости. Интересная часть разборки являетсяПочему FLD1 загружает NaN вместо этого?

 
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) 

Хотя пошагово через эту функцию, GDB говорит (ставка 0,02, задержка 2, вы можете увидеть их на стеке):

 

(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 

И после 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 

после этого, все идет в ад. Все становится слишком завышенным или недооцененным, поэтому, даже если в моей попытке AI Freeciv не было других ошибок, он выбрал бы все неправильные стратегии. Как отправка всей армии в Арктику. (Вздох, если бы я только зашел так далеко.)

Должно быть, что-то не хватает или ослепляю что-то, потому что я не могу поверить, что fld1 должен когда-либо провалиться. Тем более, что он должен потерпеть неудачу только после того, как через эту функцию пройдет несколько проходов. На предыдущих проходах FPU правильно загружает 1 в ST (0). Байты в 0x080555c6 определенно кодируют fld1 - проверяется с помощью x/... в текущем процессе.

Что дает?

ответ

6

Замечательно подходит. Что у вас здесь есть переполнение стека .

В частности, вы (или, возможно, ваш компилятор) переполнили стек x87. Он может содержать только 8 значений, и в то время, когда выдается fld1, он уже заполнен (обозначается тегом word 0000). Таким образом, fld1 переполняет стек (обозначается IE, SF, C1), что вызывает результат, который вы видите.

Что касается этого, вы могли использовать MMX-инструкции, не используя EMMS, перед использованием инструкций x87, или у вашего компилятора есть ошибка, или у вас есть код сборки где-то, что нарушает ABI вашей платформы (или библиотеку, которая вы используете, нарушает ABI).

+1

Ах, вы, ребята, рок! Благодаря! Это подтолкнуло меня к стене. Что касается того, почему это происходит: возможно, потому, что я переместил функцию, вызывающую другую, которая возвращает «double» из одного файла в другой, а в новом файле прототип функции с плавающей запятой не существует, поэтому я думаю, что компилятор никогда не выскочил возвращаемое значение из стека. Скорее всего, я ожидал, что закончится FP-стек гораздо раньше, но теперь, похоже, теперь он работает намного лучше, когда я предоставил прототип. Теперь я могу перейти к следующему segfault! –

+0

@ Бернд: Да, это, безусловно, может вызвать такую ​​проблему. –

4

Похоже, что у вас переполнение стека FPU. Слово тега FPU равно 0, что означает, что используются все регистры. Вы также можете увидеть все регистры, отмеченные как «действительные», когда я ожидаю, что некоторые будут пустыми.

Я не знаю, почему это произойдет. Может быть, у вас есть код MMX, который не выдаёт инструкцию EMMS? Или, может быть, некоторая встроенная сборка, которая не очищает стек должным образом?

Смежные вопросы