【问题标题】:C Inline assembly - Operand type mismatch for 'fst'C 内联汇编 - 'fst' 的操作数类型不匹配
【发布时间】:2012-01-05 01:43:41
【问题描述】:

嘿,我正在努力学习如何在我的 C 程序中编写汇编代码。我理解汇编中的整数,但浮点数继续让我绊倒。

double asmSqrt(double x) {
    double o;
    __asm__ ("fld %1;"
             "fsqrt;"
             "fst %0;"
             : "=g" (o)
             : "g"  (x)
    );
    return o;
}

如您所见,我只是想求 x 的平方根。但是每当我尝试编译它时,我都会得到一个操作数类型不匹配的错误。

我遵循此处使用的相同语法:http://www.codeproject.com/KB/cpp/edujini_inline_asm.aspx?display=Print

PS:我在 Windows XP 上使用 MinGW GCC

【问题讨论】:

  • Windows 上的调用约定是在寄存器 ST0 还是在 FP0 中返回浮点数?
  • 你的编译器标志是什么?
  • 我认为会不必要地刷新到堆栈,以避免您也需要实现返回。刷新到堆栈还会将您的精度降低到 64 位双精度而不是 80 位 x87。 (如果您这样做是为了速度,则需要更多;如果是为了学习,卡尔的回答为我解决了这个问题)。
  • 我没有使用任何编译器标志。我应该使用的东西??

标签: c gcc assembly mingw inline-assembly


【解决方案1】:

您需要明确指定您想要的 fldfst 指令变体。否则,编译器不知道您的操作数应该是什么大小。这段代码在这里对我有用:

__asm__ ("fldl %1  ;"
         "fsqrt    ;"
         "fstl %0  ;"
         : "=g" (o)
         : "g"  (x)
);

您可以使用反汇编程序仔细检查是否发出了 64 位 FLD 和 FST(DD/0DD/2)的正确操作码。

【讨论】:

  • 我尝试了这段代码,但它仍然不起作用:/可能是编译器的问题吗?
  • 我确信 GCC 已经能够相当成功地处理内联汇编一段时间了。我没有MinGW,所以也许它与环境有关。抱歉,这个答案没有帮助!
  • 我在我的 linux 机器上编译执行了它,你的解决方案运行良好,所以它一定是 MinGW 里面的东西,就像你说的那样。非常感谢大家的帮助!编辑:在 Windows 上,我必须像你提到的那样指定大小,并使用 o 的内存约束。我不知道为什么我没有想早点尝试:) 再次感谢大家帮助我!
【解决方案2】:

首先,你为什么要这样做?编译器可以自己做平方根。您只需调用正确的数学库函数,启用优化(因此它将内联标准函数),如果它不符合您的要求,我会感到惊讶。结果是独立于平台的(即,您可以根据需要构建 64 位,甚至可以构建整个其他架构),易于维护代码 - 更好!

如果你坚持用硬方法做,gcc 也可以在这里提供帮助(我还没有实际测试过):

double asmSqrt(double x) {
  __asm__ ("fsqrt" : "+t" (x));
  return x;
}

t 约束意味着将值放在浮点堆栈的顶部 - 您不必关心它是如何到达那里的。 + 表示将值用于输入和输出。

编辑:哦,如果你确实想自己把东西放进寄存器,那么你最好在'clobbers'部分告诉编译器,否则你可能会覆盖它存储在那里的东西。

【讨论】:

  • 学习目的。我有其他汇编代码,我使用我发布的代码,我继续收到这个错误。我刚刚隔离了 fsqrt 指令,因为我可以用 idiv 之类的东西替换它并且它工作正常。但是感谢您的工作代码
【解决方案3】:

双 sqrt1(双 n) { __asm{ 文件夹 fsqrt } }

调用方法:例如double result = sqrt1((double)10)

【讨论】:

    【解决方案4】:

    指定内存位置“=m”而不是“=g”。但最好在这里阅读本手册:http://ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html#s4

    无论如何,这里是解决方案:

    double asmSqrt(double x) {
      double o;
      __asm__ ("fld %1;"
               "fsqrt;"
               "fst %0;"
               : "=m" (o)
               : "g" (x)
      );
      return o;
    }
    

    【讨论】:

    • 在我的机器上不起作用......它与 OP 提到的关于操作数类型不匹配的错误相同。实际上,由于我使用的是 clang,所以它说:“模糊指令需要明确的后缀(可能是 'flds'、'fldl' 或 'fldt')”。
    • 谢谢,但仍有问题。它可以编译并且看起来运行良好,但是当我打印出返回值时它只有 0.0 并且它似乎也用它周围的任何代码做一些时髦的事情。 int main() { double number = 5.12343; printf("%f %f", number, asmSqrt(144.0)); getchar(); } 当我运行这个函数时,函数返回一个巨大的长浮点数。并感谢您的链接。比我迄今为止看到的任何其他网站都更好地解释了不同的约束。非常感谢。
    • 还不错;玩具示例有利于学习。 :) 我建议您从here 中选择合适的手册并在目录中搜索“约束”——t 约束列在特定于机器的部分中。还有一个部分(就在此之前)一般讨论“asm”,特别是 x86 浮点堆栈的使用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-17
    • 2016-05-18
    • 1970-01-01
    • 2019-04-01
    • 2018-02-11
    • 1970-01-01
    相关资源
    最近更新 更多