2016-06-09 49 views
1

如何在彙編器中返回64位值? 我嘗試這樣做:大會64位:如何返回一個雙精度值?

C-程序:

#include <stdio.h> 

double result=0; 
double a = 10; 
extern double func(double a); 

int main() {  
    result = func(a); 
    printf("result: %f\n", result);  
    return 0; 
    } 

大會:

 section .bss 
     x: resq 1 

     section .text 

     global func 

     func: 

     movq qword[x],xmm0 
     fld qword [x] 
     fld qword [x] 
     fadd 
     movq xmm0,qword[x] 

     ret 

它應該返回20.0而是它始終是10.0 我是怎麼了?

+3

您從不存儲結果。順便說一句,使用SSE而不是x87可能會更簡單。 – ElderBug

+0

Elderbug是正確的。 'fadd'添加st(0)和st(1)將值存儲在'st(0)'中。您不會使用堆棧頂部的值更新[x]中的值。在返回之前,也不要將額外的值從FPU堆棧彈出(如果您調用此函數5次,這會導致FPU堆棧溢出)。正如Elder指出的,除非給定的任務要求你這樣做,否則你可以使用SSE而不是FPU。 –

+0

代碼也可以簡化,但我很好奇你在編譯32位或64位代碼嗎?我假設你得到的結果是,你的可執行文件是64位的。 –

回答

2

發佈的代碼沒有評論。在談到它會幫助OP,所以......

movq qword[x],xmm0 ; Store current value in memory [Why?] 
fld qword [x]  ; Load current value from memory [Why??] 
fld qword [x]  ; Load current value from memory again 
fadd    ; Add top two stack items 
movq xmm0,qword[x] ; Read value from memory 

@ElderBug指出,OP忘記了fadd的結果存儲到內存中做最後的movq之前。

@邁克爾佩奇指出,整體功能可能是更高效的使用下面的代碼:

addsd xmm0, xmm0 ; Add input parameter to itself 
ret    ; Done! 

@邁克爾佩奇接着指出,原來的代碼留下了大量的「碎片」的在浮點堆棧上 - 沒有試圖用各種指令版本(fstpfaddp而不是fadd)對其進行清理。這爲下一個浮點函數留下了更少的空間 - 直到最終導致浮點堆棧溢出!

2

您不能混淆FPU和XMM計算。 當您計算FPU上的某些內容時,您必須將其存儲在內存中(如@Elderbug所述),然後您必須將其加載到XMM寄存器,以便在Win OS上以64位處理器上的64位處理器進行恢復。 在64位系統上仍然可以使用FPU,因此FPU的內部精度可以爲80位(如果使用正確的FPU控制字:位8,9 float32(24位尾數)= 00b 雙浮點(53位尾數)= 10B 擴展精度(64位尾數)= 11B

如果你想使用的FPU:

fld QWORD PTR x ; laod var to FPU: into ST(0) (MASM Syntax) 
fadd ST(0), ST(0) ; this adds [x]+[x] 
fstp QWORD PTR x ; store result back in var 
movsd xmm0, QWORD PTR x 

注:MOVSD總是SSE2需要(在SSE1機器上。 GP會發生故障!請參閱英特爾®64和IA-32架構軟件開發人員手冊: http://www.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html Howeve r,如果你運行的Windows8/8.1/10對你來說永遠不是問題,那麼會導致操作系統本身要求SSE2作爲系統要求。

編輯:SSE2是x86-x64中的基準(正如Peter評論中所述),因此您可以在64位上始終使用它。

如果你想使用SIMD與XMM寄存器:

movsd xmm0, QWORD PTR x 
addsd xmm0, xmm0 ; this instruction also requires SSE2 
; ok, retun xmm0 

還要注意,你也不能混淆XMM和MMX-寄存器! (指令MOVQ2DQ和MOVDQ2Q可以將它們從一個轉換到另一個,但其他指令不能)

如果您的函數使用參數,並且它應該在Windows操作系統上運行,則需要確保有效的函數prolog /結語。請參閱:https://future2048.blogspot.com

+0

x86-64以SSE2作爲基準。您的SSE1警告只適用於您在32位代碼中執行此操作的情況。 (你可能不應該使用一個調用約定,它會在沒有SSE2的機器上運行的代碼中返回xmm regs中的雙精度,但如果你只想使用SSE1,你仍然可以使用['movlps'](http:但不要因爲它會與寄存器的舊內容合併,而不是將高64位清零(錯誤依賴xmm寄存器的舊值) ) –

+0

此外,重新:x87精度控制的初始設置:請參閱[這是布魯斯道森關於FP的一系列優秀文章](https://randomascii.wordpress.com/2012/03/21/intermediate-floatingpoint -精確/)。 VC++的CRT代碼將x87單元設置爲53位尾數精度,至少對於32位可執行文件。我沒有重新閱讀整篇文章,看看它何時離開。我想我已經讀了一些關於directx改變x87精度的內容。很高興我不使用Windows。 :) –