如何在Assembler中返回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 我错了什么?
答案 0 :(得分:2)
@Michael Petch指出,使用以下代码,整个函数可以更多更高效:
addsd xmm0, xmm0 ; Add input parameter to itself
ret ; Done! (return values go in xmm0)
x86-64在XMM寄存器中传递/返回double
,而不是内存或x87堆栈。(适用于x86-64 System V ABI /调用约定和Windows x64 。请参阅the x86 tag wiki)
发布的代码没有评论。评论它会对OP有所帮助,所以......
;; Buggy original version with comments
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] ; reload original value from memory, unmodified
@ElderBug注意到OP在执行最终fadd
之前忘记将movq
的结果存储到内存中,因此该函数只返回其输入,如
double foo(double x) { return x; }
但是在x87堆栈上留下了垃圾。
@Michael Petch继续注意到原始代码在浮点堆栈上留下了大量的“碎片” - 没有尝试用各种pop
版本的指令清除它({{ 1}},或fstp
代替faddp
)。这为下一个浮点函数留下了更少的空间 - 直到最后导致浮点堆栈溢出,导致意外的NaN!
答案 1 :(得分:2)
您无法混淆FPU和XMM计算。 当你在FPU上计算某些东西时,你必须将它(如@Elderbug所说)存储在内存中然后你必须将它加载到XMM寄存器以在Win OS上的x64上的64位proc上返回它。 在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 但是,如果您运行的Windows8 / 8.1 / 10对您来说永远不是问题,那么导致操作系统本身请求SSE2作为系统要求。
编辑:SSE2是x86-x64的基线(正如Peter Cordes在评论中所述),所以你总是可以在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 / epilog。见:https://future2048.blogspot.com