use*_*793 0 x86 assembly compiler-errors mismatch
我在网上找到了一些建议。
我有一个类似的问题,但是所有建议都没有帮助(或者我没有根据我的程序正确弄清楚如何实现它们)。
该代码如asm(...)在C程序中那样插入。
-masm=intel使用编译后,使用时:
asm ("FLD EBX \n" "FSQRT \n" "FST EBX \n").
Run Code Online (Sandbox Code Playgroud)
我收到编译错误:
“错误:'fld'的操作数类型不匹配”“” ...'fst'的不匹配“”。
在这些命令之前,EBX持有一些整数正值。
那么获取ebx = sqrt(ebx)的正确方法是什么?
您应该在现代代码中将SSE / SSE2用于sqrt,而不是x87。您可以使用一条指令将gp寄存器中的整数直接转换为xmm寄存器中的double。
cvtsi2sd xmm0, ebx
sqrtsd xmm0, xmm0 ; sd means scalar double, as opposed to SIMD packed double
cvttsd2si ebx, xmm0 ; convert with truncation (C-style cast)
; cvtsd2si ecx, xmm0 ; rounded to nearest integer (or whatever the current rounding mode is)
Run Code Online (Sandbox Code Playgroud)
这也适用于64位整数(rbx),但请注意,double它只能精确表示不超过2 ^ 53(尾数大小)的整数。如果要检查整数是否是理想的平方,可以使用float sqrt,然后对整数结果进行尝试乘法。((a*a) == b)
请参阅x86,以获得指向指南,教程和手册的链接。
请注意,将此代码插入C程序的中间是完全错误的方法。GNU C内联汇编是执行汇编的最困难的方法,因为您必须真正了解所有内容才能正确地执行约束。弄错它们可能导致其他周围的代码以微妙且难以调试的方式破坏,而不仅仅是行内汇编错误的事情。有关更多信息,请参见x86标签Wiki。
如果需要int a = sqrt((int)b),则将其编写为代码,然后让编译器为您生成这三个指令。一定要阅读并理解编译器的输出,但不要只是使用盲目地将一个序列放入中间asm("")。
例如:
#include <math.h>
int isqrt(int a) { return sqrt(a); }
Run Code Online (Sandbox Code Playgroud)
编译为(不带-ffast-math的gcc 5.3):
pxor xmm0, xmm0 # D.2569
cvtsi2sd xmm0, edi # D.2569, a
sqrtsd xmm1, xmm0 # tmp92, D.2569
ucomisd xmm1, xmm1 # tmp92, tmp92
jp .L7 #,
cvttsd2si eax, xmm1 # D.2570, tmp92
ret
.L7:
sub rsp, 8 #,
call sqrt #
add rsp, 8 #,
cvttsd2si eax, xmm0 # D.2570, tmp92
ret
Run Code Online (Sandbox Code Playgroud)
我想sqrt()必须在某些类型的错误上设置errno。:/
与-fno-math-errno:
pxor xmm0, xmm0 # D.2569
cvtsi2sd xmm0, edi # D.2569, a
sqrtsd xmm0, xmm0 # tmp92, D.2569
cvttsd2si eax, xmm0 # D.2570, tmp92
ret
Run Code Online (Sandbox Code Playgroud)
这样做pxor是为了打破对xmm0先前内容的错误依赖,因为cvtsi2sd做出了奇怪的设计决定,即不修改dest向量reg的上半部分。仅在要将转换结果插入到现有向量中时才有用,但是已经cvtdq2pd进行了打包转换。(而且他们可能没有考虑64位整数,因为当Intel发布SSE2时AMD64仍处于起步阶段)。