简体   繁体   中英

FASM assembly how to use the FPU in 64 bit programs

I have this code in FASM that calculates a measurement using the FPU that works great in 32 bit programs. How would I convert it so it would run in 64 bit program. when I use this code in the 64 bit program it gives me 0.00000 instead of a number like 54.24457 I think it is something with the FPU instructions but I don't know enough about assembly or 64 bit programming to get it to work

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

} 

thanks

The calling convention for doubles in 64 bit mode uses xmm registers, you'll have to adjust your cinvoke lines if it even supports that. Otherwise just use manual code, something like:

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

Disclaimer: I don't have windows to test.


Update : cinvoke is a helper macro that tries to do the right thing for calling a C function. You are passing the double in two parts, which might work for a stack-based calling convention, but in 64 bit mode registers are used to pass arguments. For doubles you need to use xmm registers. The cinvoke macro might know how to do that, but you certainly need to help it by telling it you want to pass a double. The code I posted is a hopefully correct calling sequence for sprintf , as such you can use it instead of the cinvoke .


Update #2 : msdn says that for varargs functions (and sprintf is one) floating point arguments must be duplicated in both integer and xmm registers. Here is a complete console program multiplying 2 values using the FPU:

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

Note this is for nasm but you should be able to adapt this to your needs. I have tested this using wine.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM