10

当我尝试编译此代码时:

#include <stdio.h>

main(int argc, char *argv[]) {
   double y = 0;

   __asm__ ("fldl $150;"
            "fsqrt;"
            "fstl %0;" : : "g" (y) );

   printf("%f\n", y);


   return 0;
}

我收到此错误:

sqrt.c: Assembler messages:
sqrt.c:6: Error: suffix or operands invalid for `fld'

为什么这不起作用?为什么我不能将数字“150”压入堆栈以进行浮点运算?

4

5 回答 5

9

我不知道有一种汇编语言支持立即使用的文字浮点常量。通常的方法是声明包含浮点常量的初始化存储并引用它:

const1:     dq  1.2345
...
     fldl    const1

对于您给出的示例,可以更直接地执行此操作:

printf ("%f\n", sqrt (150));

否则,这一定是一个人为的复杂项目,也许是功课。

于 2011-06-29T00:36:28.477 回答
5

尝试这样的事情

push $0x????????
push $0x????????
fldl (%esp)
addl $8,%esp

其中 ?????????? 被双常数的 IEEE 表示所取代。这种方法的优点是它在正常和位置无关(PIC,即共享库)代码中同样有效。

于 2011-06-29T01:22:24.013 回答
2

t约束

根据 GCC 文档https://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html#Machine-Constraints

80387 浮点堆栈的顶部 (%st(0))。

所以我们可以这样做:

#include <assert.h>

int main(void) {
    double io = 4.0;
    __asm__ (
        "fsqrt"
        : "+t" (io)
        :
        :
    );
    assert(io == 2.0);
    return 0;
}

GitHub 上游.

Refresher:+表示io将用作输入和输出。

在 Ubuntu 19.04 中测试。

GNU GAS ARM 程序集支持它

例如在 ARMv8 中:

主程序

#include <assert.h>

int main(void) {
    float my_float = 1.5;
    __asm__ (
        "fmov s0, 1.0;"
        "fadd %s[my_float], %s[my_float], s0;"
        : [my_float] "+w" (my_float)
        :
        : "s0"
    );
    assert(my_float == 2.5);
}

GitHub 上游.

编译并运行:

aarch64-linux-gnu-gcc -o main.out -static -std=gnu99 main.c
qemu-aarch64 ./main.out

该修饰符在: ARMv8 浮点输出内联汇编%s中提到

它也适用于 ARMv7。

但是,由于某种原因,它仅适用于浮点指令fmov,例如,以下 ARMv7 尝试无法汇编:

mov r0, 1.5

有错误:

Error: garbage following instruction -- `mov r0,1.5'

大概是因为它使用了mov指令,该指令作用于通用寄存器而不是浮点寄存器。

然而,也许这并不重要,因为在大多数情况下,您只想对浮点寄存器进行浮点运算,然后执行fcmp如下操作vmrs

vmov s0, 1.5
vmov s1, 2.5
fadds s2, s0, s1
vmov s3, 4.0
/* Compare two floating point registers. Stores results in fpscr:
 * (floating point status and control register).
 */
vcmp.f32 s2, s3
/* Move the nzcv bits from fpscr to apsr */
vmrs apsr_nzcv, fpscr
/* This branch uses the Z bit of apsr, which was set accordingly. */
beq theyre_equal

GitHub 上游.

GNU GAS 对每个拱门的语法都有微妙的不同,这总是让我感到好笑!

但是我找不到十六进制浮点文字语法:How to use hexadecimal floating point literals in GNU GAS?

在 Ubuntu 18.04 上测试。

于 2018-10-20T13:22:19.520 回答
1

指令的唯一有效操作数fld是内存或浮点堆栈寄存器。

(此外,您已将块指定y为输入操作数asm,而它应该是输出。将其限制为内存("m"而不是"g")可能更安全。)

如果你真的想用内联汇编来做到这一点:

#include <stdio.h>

int main(void)
{
   double y;
   const double k = 150.0;

   __asm__ ("fldl %1;"
            "fsqrt;"
            "fstl %0;" : "=m" (y) : "m" (k) );

   printf("%f\n", y);

   return 0;
}
于 2011-06-29T01:06:10.763 回答
-3

您可以通过让 PHP 为您预处理文字来绕过许多拒绝支持浮点文字的汇编程序。(rawSingleHex 取自这里)。在一个完美的世界中,C 预处理器就足够了,但目前还不是这样。

<?php
function rawSingleHex($num) {
    return '0x' . strrev(unpack('h*', pack('f', $num))[1]);
}
?>

#include <stdio.h>

int main(int argc, char **argv) {
   float y = 0;

   __asm__ ("pushl $<?php echo rawSingleHex(150);?>\n"
            "fsqrt\n"
            "fstl %0\n" : : "g" (y));

   printf("%f\n", y);


   return 0;
}

运行 php 生成 c 文件,然后运行 ​​c 编译器来编译你的程序:P

于 2017-10-26T04:48:36.517 回答