如何使用内联汇编指定直接浮点数?

问题描述 投票:9回答:5

当我尝试编译此代码时:

#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”推入堆栈进行浮点运算?

c gcc assembly inline-assembly x87
5个回答
9
投票

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

const1:     dq  1.2345
...
     fldl    const1

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

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

否则,这必须是人工复杂的项目,也许是家庭作业。


5
投票

尝试这样的事情

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

其中???????被替换为双常数的IEEE表示。该方法的优点在于它在正常和位置无关(PIC,即共享库)代码中同样良好地工作。


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;
}

1
投票

t约束

根据海湾合作委员会文件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 upstream

复习:+意味着io将用作输入和输出。

在Ubuntu 19.04中测试过。

GNU GAS ARM程序集支持它

例如。在ARMv8中:

main.c中

#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 upstream

编译并运行:

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

%s修饰符在:ARMv8 floating point output inline assembly中提到

它也适用于ARMv7。

但是,出于某种原因,它仅适用于浮点指令,例如fmov,例如mov r0, 1.5 。以下ARMv7尝试无法组装:

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 upstream

How to use hexadecimal floating point literals in GNU GAS?

它永远不会让我开心,GNU GAS如何为每个拱门提供微妙的语法!

然而,我无法找到hex float literal语法:here

在Ubuntu 18.04上测试过。


-2
投票

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

qazxswpoi

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

© www.soinside.com 2019 - 2024. All rights reserved.