1. ホーム
  2. assembly

[解決済み] ST(0)をEAXに移動させる方法は?

2022-03-04 01:56:08

質問

こんにちは、私はx86 FPUのアセンブリを学んでいます。 簡単な質問で、答えが見つからないものがあります。

から値を移動させる方法 ST(0) ( FPUのトップ スタック)から EAX ?

もあります。
はこのコードで合っていますか?

; multiply (dot) two vectors of 3 floats passed by pointers as arg 1 arg 2
; passings are ok I think, but not sure if multiplies-adds are ok

    push    ebp                                     
    mov     ebp, esp                                
    mov     eax, dword [ebp+8H]                     
    mov     edx, dword [ebp+0CH]                    

    fld     qword [eax]                             
    fmul    qword [edx]                             
    fld     qword [eax+4H]                          
    fmul    qword [edx+4H]                          
    fld     qword [eax+8H]                          
    fmul    qword [edx+8H]                          
    faddp   st1, st(0)                              
    faddp   st1, st(0)                            
    fstp    qword [ebp+10H]     ; here I vould prefer 'mov eax, st0'

    pop     ebp                                   
    ret                                           

解決方法は?

そうしなければならない本当の理由はありません。次のことを忘れないでください。 EAX は32ビットレジスタですが、FPUのレジスタはすべて80ビット幅です。これは、FPUがデフォルトで80ビット浮動小数点数で計算を行うからです。そのため、FPUレジスタから汎用レジスタにデータを移動すると、データロスが発生します。どうしてもそういうことをしたい場合は、次のようにしてみてください(スタックスペースに余裕があることが前提です).

sub esp, 4           ; or use space you already reserved
fstp dword [esp]
mov eax, [esp]       ; or better,  pop eax
add esp, 4

この命令は、現在FPUスタックの一番上にあるfloatを32ビットに丸め、それを一時的なスタックロケーションに書き込み、FPUスタックにロードします。 float (binary32)ビットパターンを EAX そして、使用したスタック領域を整理する。


このようなことは、ほとんどありません。 標準的な呼び出し規約では、float / double / long doubleの値は st(0) そのため、Cコンパイラはそこに double foo() 関数が値を残すようにします。 (または xmm0 SSE/SSE2 の場合)。

FPのビットパターンで整数の操作やテストをしたい場合にのみ必要です。 (例: Cでタイプパンを実装する場合 memcpy から float から uint32_t ). 例) 有名ですが、今ではほとんど使われなくなった高速近似逆引きの sqrtf マジックナンバーハック Quakeのソースコードで使用されています。