Pergunta

Eu tenho uma função de uma linha C que é apenas return value * pow(1.+rate, -delay); - Ele desconta um valor futuro para um valor presente. A parte interessante da desmontagem é

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)

Enquanto o passo único por essa função, diz o GDB (a taxa é de 0,02, o atraso é 2; você pode vê-los na pilha):

(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

E depois do 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

Depois disso, tudo vai para o inferno. As coisas ficam grosseiras ou subvalorizadas, portanto, mesmo que não houvesse outros bugs na minha tentativa de AI frequent, ele escolheria todas as estratégias erradas. Como enviar todo o exército para o Ártico. (Suspiro, se eu estivesse chegando tão longe.)

Devo estar perdendo algo óbvio, ou ficando cego por algo, porque não posso acreditar que fld1 deve jamais falhar. Ainda menos que deve falhar apenas após um punhado de passes por essa função. Em passes anteriores, a FPU carrega corretamente 1 em ST (0). Os bytes em 0x080555c6 codificam definitivamente fld1 - Verificado com x/... no processo de execução.

O que da?

Foi útil?

Solução

Notavelmente apropriado. O que você tem aqui é um PACK Overflow.

Especificamente, você (ou possivelmente seu compilador) transbordou a pilha x87. Só pode conter 8 valores e no momento em que o fld1 é emitido, já está cheio (indicado pela palavra tag de 0000). Assim, o fld1 transborda a pilha (indicada por IE, SF, C1) que causa o resultado que você está vendo.

Quanto ao motivo pelo qual isso está acontecendo, você pode ter usado instruções MMX sem usar um EMMS Antes de usar as instruções X87, ou seu compilador possui um bug, ou você tem um código de montagem em algum lugar que viola o ABI da sua plataforma (ou uma biblioteca que você está usando viola o ABI).

Outras dicas

Parece que você tem um transbordamento de pilha de FPU. A palavra de tag FPU é 0, o que significa que todos os registros são usados. Você também pode ver todos os registros marcados como "válidos", quando eu esperaria que alguns estivessem vazios.

Não sei por que isso aconteceria. Talvez você tenha algum código MMX que não emite o EMMS instrução? Ou talvez alguma montagem em linha que não limpe a pilha corretamente?

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top