FASM汇编如何在64位程序中使用FPU

时间:2013-10-16 15:00:35

标签: assembly 32bit-64bit x86-64 fpu fasm

我在FASM中有这个代码,它使用在32位程序中运行良好的FPU计算测量值。我将如何转换它以便它将在64位程序中运行。当我在64位程序中使用这个代码时,它给我0.00000而不是像54.24457这样的数字我觉得它是FPU指令的东西,但是我对组装或64位编程知之甚少以使它工作

macro calculateresultlengthX {

;calculate result length x

;formula is resultlengthX = resultlengthXpixelstextbox / MeasuredlengthXpixelstextbox * MeasuredlengthXtextbox

;read in resultlengthXinpixelstextbox

invoke GetDlgItemTextA, [hwnd], resultlengthxpixelstextbox, bufferbuffer1, 100
cinvoke sscanf, bufferbuffer1, "%f", buffer1 

;read in MeasuredlengthXinpixelstextbox

invoke GetDlgItemTextA, [hwnd], measuredlengthxpixelstextbox, bufferbuffer2, 100
cinvoke sscanf, bufferbuffer2, "%f", buffer2

;resultlengthXpixels / MeasuredlengthXpixels

finit
fld dword [buffer1]
fld dword [buffer2] 
fdivp
fstp qword [buffer3]  

cinvoke sprintf, addr buffer1, "%.16lf", dword [buffer3], dword [buffer3 + 4]
invoke SetDlgItemTextA,[hwnd],resultlengthxtextbox,addr buffer1

;read in ResultlengthXtextbox to get the temporary value

invoke GetDlgItemTextA, [hwnd],resultlengthxtextbox, bufferbuffer1, 100
cinvoke sscanf, bufferbuffer1, "%f", buffer1

;read in MeasuredlengthXtextbox

invoke GetDlgItemTextA, [hwnd],measuredlengthxtextbox, bufferbuffer2, 100
cinvoke sscanf, bufferbuffer2, "%f", buffer2

;answer * MeasuredlengthXtextbox

finit
fld dword [buffer1]
fld dword [buffer2] 
fmulp
fstp qword [buffer3]  

cinvoke sprintf, addr buffer1, "%.16lf", dword [buffer3], dword [buffer3 + 4]
invoke SetDlgItemTextA,[hwnd],resultlengthxtextbox,addr buffer1

} 

感谢

1 个答案:

答案 0 :(得分:1)

64位模式下双精度调用约定使用xmm寄存器,如果它甚至支持,你必须调整cinvoke行。否则只需使用手动代码,例如:

lea rcx, [buffer1]
lea rdx, [format]
movsd xmm0, [buffer3]
sub rsp, 32
call sprintf
add rsp, 32

免责声明:我没有窗户可供测试。


更新cinvoke是一个帮助宏,它尝试为调用C函数做正确的事情。您将两部分传递给两个部分,这可能适用于基于堆栈的调用约定,但在64位模式下,寄存器用于传递参数。对于双打,您需要使用xmm个寄存器。 cinvoke宏可能知道如何做到这一点,但你肯定需要通过告诉它想要传递双精度来帮助它。我发布的代码是sprintf的正确调用序列,因此您可以使用它代替cinvoke


更新#2 msdn says对于varargs函数(并且sprintf为1),浮点参数必须在整数和xmm寄存器中重复。 这是一个完整的控制台程序,使用FPU乘以2个值:

global main
extern scanf
extern printf
main:
    sub rsp, 40 ; shadow space + stack alignment
    lea rcx, [infmt]
    lea rdx, [op1]
    call scanf
    lea rcx, [infmt]
    lea rdx, [op2]
    call scanf
    fld dword [op1]
    fld dword [op2]
    fmulp
    fstp qword [result]
    lea rcx, [outfmt]
    movsd xmm1, [result]
    mov rdx, [result]
    call printf
    add rsp, 40
    xor eax, eax
    ret
section .data
op1: dd 0
op2: dd 0
result: dq 0
infmt: db "%f", 0
outfmt: db "%.16lf", 0

请注意这是nasm,但您应该能够根据自己的需要进行调整。我用葡萄酒测试了这个。