【问题标题】:FASM assembly how to use the FPU in 64 bit programsFASM 汇编如何在 64 位程序中使用 FPU
【发布时间】:2013-10-24 18:30:40
【问题描述】:

我在 FASM 中有这段代码,它使用在 32 位程序中运行良好的 FPU 计算测量值。我将如何转换它以便它可以在 64 位程序中运行。当我在 64 位程序中使用此代码时,它给了我 0.00000 而不是像 54.24457 这样的数字>

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

} 

谢谢

【问题讨论】:

  • AFAIK,所有 FPU 指令的条目在手册中都说“该指令的操作在非 64 位模式和 64 位模式下是相同的”。也许是别的?
  • 我们不使用 64 位的 x87 代码。我们改用 SSE 指令。每个 x64 处理器都支持 SSE。不幸的是,x87 指令在 64 位模式下仍然可用;所以如果你坚持你仍然可以使用它们,但你的代码将是 slllooooowwwwww。

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


【解决方案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


更新 #2msdn says 对于可变参数函数(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 测试过了。

【讨论】:

  • 对不起,我真的不明白你的回答。我用你给我的代码换掉了 5 行 FPU 代码,它编译但当我试图计算一个值时崩溃了。我会研究 xmm。我不明白你说的关于 cinvoke 的内容
  • 我尝试将第一行 cinvoke 转换为新代码,并在其后放置一个 ret 来测试它。它编译得很好,但是当我尝试按下 calc 按钮时它崩溃并说 Windows 可以检查解决方案和所有这些东西。
  • 在数据中我添加了这个 format1 db "%f",13,0 并且在代码中我尝试了这个调用 GetDlgItemTextA, [hwnd], resultlengthxpixelstextbox, bufferbuffer1, 100 lea rcx, [bufferbuffer1] lea rdx, [format112] movsd xmm0, [buffer1] sub rsp, 32 call sprintf add rsp, 32 ;cinvoke sscanf, bufferbuffer1, "%f", buffer1 ret 我也试过把 buffer1 和 bufferbuffer1 颠倒过来,但它仍然崩溃,请你帮忙我也像buffer1等所有缓冲区都是dq?谢谢
  • 我似乎仍然无法让这段代码工作。它在 call sscanf 行崩溃我在 fasm 网站上问了这个问题并得到了这个代码,但它似乎给出了一个空文本框mov dword [buffer1],20.0 mov dword [buffer2],2.0 movss xmm0,[buffer1] movss xmm1, [buffer2] divss xmm0,xm​​m1 ; char buffer lea rdi,[buffer3] lea rsi,[format0] xor rdx,rdx call qword [sprintf] ;结果字符串现在应该写在 buffer3 buffer1: dd $00000000 buffer2: dd $00000000 buffer3: db 256 dup($00) format0: db "%0.5f",$00
猜你喜欢
  • 1970-01-01
  • 2012-05-29
  • 1970-01-01
  • 2011-03-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-13
相关资源
最近更新 更多