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