Почему FLD1 вместо этого загружает NaN? - PullRequest
4 голосов
/ 14 мая 2010

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

0x080555b9 :      neg    %eax
0x080555bb :      push   %eax
0x080555bc :      fildl  (%esp)
0x080555bf :      lea    0x4(%esp),%esp
0x080555c3 :      fldl   0xfffffff0(%ebp)
<b>0x080555c6 :      fld1   </b>
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

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

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

Что дает?

Ответы [ 2 ]

6 голосов
/ 14 мая 2010

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

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

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

4 голосов
/ 14 мая 2010

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

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

...