Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Gcc 汇编64位:如何返回双精度值?_Gcc_Assembly_Nasm - Fatal编程技术网

Gcc 汇编64位:如何返回双精度值?

Gcc 汇编64位:如何返回双精度值?,gcc,assembly,nasm,Gcc,Assembly,Nasm,如何在汇编程序中返回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; } 它应该返回20.0,但始终是10.0 我做错了什么 @M

如何在汇编程序中返回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;
   }
它应该返回20.0,但始终是10.0
我做错了什么

@Michael Petch指出,使用以下代码,整个函数的效率可能会更高:

addsd xmm0, xmm0   ; Add input parameter to itself
ret                ; Done!  (return values go in xmm0)
x86-64在XMM寄存器中传递/返回
double
,而不是内存或x87堆栈。
(适用于x86-64系统V ABI/调用约定和Windows x64。请参阅中的链接)


发布的代码没有注释。评论它会对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在执行最终的
movq
之前忘记将
fadd
的结果存储到内存中,因此此函数只返回其输入,如
double foo(double x){return x;}
但在x87堆栈上留下垃圾



@Michael Petch接着指出,原始代码在浮点堆栈上留下了大量的“碎片”——没有人试图用各种
pop
版本的指令来清理它(
fstp
,或
faddp
,而不是
fadd
)。这就减少了下一个浮点函数的空间——直到最后导致浮点堆栈溢出,导致意外的NaN

@Michael Petch指出,使用以下代码,整个函数的效率可能会更高:

addsd xmm0, xmm0   ; Add input parameter to itself
ret                ; Done!  (return values go in xmm0)
x86-64在XMM寄存器中传递/返回
double
,而不是内存或x87堆栈。
(适用于x86-64系统V ABI/调用约定和Windows x64。请参阅中的链接)


发布的代码没有注释。评论它会对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在执行最终的
movq
之前忘记将
fadd
的结果存储到内存中,因此此函数只返回其输入,如
double foo(double x){return x;}
但在x87堆栈上留下垃圾



@Michael Petch接着指出,原始代码在浮点堆栈上留下了大量的“碎片”——没有人试图用各种
pop
版本的指令来清理它(
fstp
,或
faddp
,而不是
fadd
)。这就减少了下一个浮点函数的空间——直到最后导致浮点堆栈溢出,导致意外的NaN

不能混淆FPU和XMM计算。 当您在FPU上计算某些内容时,必须将其存储在内存中(正如@Elderbug所说),然后必须将其加载到XMM寄存器,以在Win OS上x64上的64位进程上返回。 在64位系统上使用FPU仍有优势,因为FPU的内部精度可以是80位(如果使用正确的FPU控制字:位8,9浮点32(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体系结构软件开发人员手册: 但是,如果您运行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有效。请参阅:

您不能混淆FPU和XMM计算。 当您在FPU上计算某些内容时,必须将其存储在内存中(正如@Elderbug所说),然后必须将其加载到XMM寄存器,以在Win OS上x64上的64位进程上返回。 在64位系统上使用FPU仍有优势,因为FPU的内部精度可以是80位(如果使用正确的FPU控制字:位8,9浮点32(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体系结构软件开发人员手册: 但是,如果您运行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有效。请参阅:

您从不存储结果。顺便说一句,使用SSE而不是x87可能更简单。Elderbug是正确的。
fadd
添加了st(0)和st(1)将值存储在
st(0)中
。不使用堆栈顶部的值更新[x]中的值。也不在返回之前从FPU堆栈中弹出额外的值(如果调用此函数5次,将导致FPU堆栈溢出问题)。正如Elder指出的,除非给定的任务要求您这样做,否则您可以使用SSE而不是FPU。代码也可以简化,但我很好奇您是为32位还是64位代码编译的?我假设从您得到的结果来看,您的可执行文件是64位的。如果您可以使用SSE,您可以使用这样的指令
section.text;全局函数;函数