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

Assembly FASM汇编如何在64位程序中使用FPU,assembly,32bit-64bit,x86-64,fpu,fasm,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 = resultlengthXpixel

我在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

} 

感谢

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

learcx[buffer1]
lea rdx,[格式]
movsd xmm0,[buffer3]
副区长,32
呼叫sprintf
加上rsp,32
免责声明:我没有要测试的windows


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


更新#2:对于varargs函数(和
sprintf
是一个函数),浮点参数必须在整数和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的,但您应该能够根据自己的需要进行调整。我已经使用wine对此进行了测试。

AFAIK,所有FPU指令的条目都会在手册中显示“此指令在非64位模式和64位模式下的操作相同”。也许是别的原因?我们不使用64位的x87代码。我们使用SSE指令。每个x64处理器都支持SSE。不幸的是,x87指令在64位模式下仍然可用;所以,如果你坚持你仍然可以使用它们,但你的代码将是sllloooww。对不起,我真的不明白你的答案。我用u给我的代码交换了5行FPU代码,它被编译了,但当我试图计算一个值时崩溃了。我将研究xmm。我不明白你说的关于cinvokeI的什么我试着把第一行cinvoke转换成新代码,我在它后面放了一个ret来测试它。它编译得很好,但当我试图按下calc按钮时,它崩溃了,并说windows可以检查解决方案和所有这些东西。在数据中,我添加了这个format1 db“%f”,13,0,在代码中,我尝试了调用GetDlgItemTextA[hwnd],ResultLength XpixelsTextBox,bufferbuffer1,100 lea rcx,[bufferbuffer1]lea rdx,[format112]movsd xmm0,[buffer1]子rsp,32呼叫sprintf添加rsp,32;cinvoke sscanf,bufferbuffer1,“%f”,buffer1 ret我也试过反转buffer1和buffer1,但它仍然崩溃。你能帮我一下吗?所有的缓冲区,如buffer1等都是dq吗?谢谢,我似乎仍然无法让这段代码正常工作。它在呼叫sscanf线路上崩溃了。我在fasm网站上问了这个问题,得到了这段代码,但它似乎给出了一条空文本xmov-dword[buffer1],20.0 mov-dword[buffer2],2.0 movss-xmm0,[buffer1]movss-xmm1,[buffer2]divss-xmm0,xmm1;char-buffer-lea-rdi,[buffer3]lea-rsi,[format0]xor-rdx,rdx调用qword[sprintf];结果字符串现在应该写入buffer3 buffer1:dd$00000000 buffer2:dd$00000000 buffer3:db 256 dup($00)format0:db“%0.5f”,$00