assembly - 组装x86中的Sqrt

标签 assembly compiler-errors x86 mismatch

我在网上找到了一些建议。

  • C Inline assembly - Operand type mismatch for 'fst'
  • Why am I getting these assembler errors?
  • Why will I have operand type mismatch error when compiling the assembly codes with gcc?

  • 我有一个类似的问题,但是所有建议都没有帮助(或者我没有根据我的程序正确弄清楚如何实现它们)。

    该代码作为asm(...)插入到C程序中。

    使用-masm=intel编译后,使用时:
    asm ("FLD EBX \n" "FSQRT \n" "FST EBX \n").
    

    我收到编译错误:

    “错误:'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)
    

    这也适用于64位整数(rbx),但是请注意double只能精确表示最大约2 ^ 53(尾数大小)的整数。如果要检查整数是否是理想的平方,可以使用float sqrt,然后对整数结果进行尝试乘法。 ((a*a) == b)

    请参阅以获取指南,教程和手册的链接。

    请注意,将此代码插入C程序的中间是完全错误的方法。 GNU C内联汇编是执行汇编的最困难的方法,因为您必须真正了解所有内容才能正确地执行约束。弄错它们可能导致其他周围的代码以微妙且难以调试的方式破坏,而不仅仅是您在处理内联汇编错误时所做的事情。有关更多信息,请参见x86标签Wiki。

    如果需要int a = sqrt((int)b),则将其写入代码中,然后让编译器为您生成这三个指令。一定要阅读并理解编译器的输出,但不要仅仅使用asm("")盲目地将其序列放入中间。

    例如。:
    #include <math.h>
    int isqrt(int a) { return sqrt(a); }
    

    compiles to(不带-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
    

    我猜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
    
    pxor旨在打破对xmm0先前内容的错误依赖,因为cvtsi2sd做出了奇怪的设计决定,即不修改dest vector reg的上半部分。仅在要将转换结果插入到现有 vector 中时才有用,但是已经有cvtdq2pd进行打包转换。 (而且他们可能没有考虑64位整数,因为当Intel发布SSE2时AMD64仍处于起步阶段)。

    关于assembly - 组装x86中的Sqrt,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35747811/

    相关文章:

    c - 使用 SSE 模拟标准 Math.pow 函数

    java - 程序丢失一个增量和两个 `` printf``s

    c++ - 奇怪的编译器错误

    reactjs - react - 未捕获的类型错误 : Cannot read property 'Component' of undefined

    c++ - 为什么在 32 位 x86 架构上默认对齐 `int64_t` 8 字节?

    linux - shellcode错误段错误(核心转储)

    c++ - 使用 xchg 时需要 mfence 吗

    string - 在 MASM 中使用汇编代码替换字符串中的字符

    c++ - CImg 的编译错误

    ruby - 在 64 位操作系统上安装 32 位 Ruby