Сборка FASM как использовать FPU в 64 битных программах

У меня есть этот код в FASM, который вычисляет измерение с использованием FPU, который отлично работает в 32-битных программах. Как бы я преобразовал его, чтобы он работал в 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

} 

Спасибо


person Darrin Woolit    schedule 16.10.2013    source источник
comment
Насколько я знаю, записи для всех инструкций FPU говорят, что эта инструкция работает одинаково в не 64-битных режимах и 64-битном режиме в руководстве. Может, это что-то другое?   -  person harold    schedule 16.10.2013
comment
Мы не используем код x87 в 64-битной версии. Вместо этого мы используем инструкции SSE. Все процессоры x64 поддерживают SSE. К сожалению, инструкции x87 все еще можно использовать в 64-битном режиме; поэтому, если вы настаиваете, вы все равно можете их использовать, но ваш код будет slllooooowwwwww.   -  person Johan    schedule 18.10.2013


Ответы (1)


Соглашение о вызовах для двойников в 64-битном режиме использует регистры xmm, вам придется настроить свои строки cinvoke, если оно даже поддерживает это. В противном случае просто используйте ручной код, например:

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

Отказ от ответственности: у меня нет Windows для тестирования.


Обновление: cinvoke – это вспомогательный макрос, который пытается правильно выполнить вызов функции C. Вы передаете double двумя частями, что может работать для соглашения о вызовах на основе стека, но в 64-битном режиме регистры используются для передачи аргументов. Для двойников вам нужно использовать xmm регистров. Макрос cinvoke может знать, как это сделать, но вам, безусловно, нужно помочь ему, сказав, что вы хотите передать двойное значение. Код, который я разместил, является, надеюсь, правильной последовательностью вызова для sprintf, поэтому вы можете использовать его вместо cinvoke.


Обновление №2: msdn сообщает, что для varargs (и sprintf является одним из них) аргументы с плавающей запятой должны дублироваться как в целых регистрах, так и в регистрах xmm. Вот полная консольная программа, умножающая 2 значения с помощью 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

Обратите внимание, что это для nasm, но вы сможете адаптировать его к своим потребностям. Я проверил это с помощью вина.

person Jester    schedule 16.10.2013
comment
Извините, но я действительно не понимаю вашего ответа. Я заменил 5 строк кода FPU кодом, который вы мне дали, и он скомпилировался, но разбился, когда я попытался вычислить значение. Я посмотрю на xmm. Я не понимаю, что вы сказали о Cinvoke - person Darrin Woolit; 16.10.2013
comment
Я попытался преобразовать только первую строку cinvoke в новый код и поставил после нее рет, чтобы проверить его. он скомпилирован нормально, но когда я попытался нажать кнопку расчета, он вылетает и говорит, что Windows может проверить решение и все такое. - person Darrin Woolit; 17.10.2013
comment
в данных я добавил этот формат1 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 Я также пытался поменять местами буфер1 и буфербуфер1, и все равно произошел сбой. Не могли бы вы помочь мне, также все буферы, такие как буфер1 и т. д., являются dq? Спасибо - person Darrin Woolit; 17.10.2013
comment
Я до сих пор не могу заставить этот код работать. Он падает в строке вызова sscanf. Я задал этот вопрос на сайте fasm и получил этот код, но, похоже, он дает пустой текстовый boxmov dword [buffer1], 20.0 mov dword [buffer2], 2.0 movss xmm0, [buffer1] movss xmm1, [буфер2] divss xmm0,xmm1 ; char buffer lea rdi,[buffer3] lea rsi,[format0] xor rdx,rdx call qword [sprintf] ; строка результата теперь должна быть записана в буфер3 буфер1: dd $00000000 буфер2: dd $00000000 буфер3: db 256 dup($00) format0: db %0.5f,$00 - person Darrin Woolit; 20.10.2013