簡體   English   中英

如何使用內聯匯編指定立即浮點數?

[英]How do I specify immediate floating point numbers with inline assembly?

當我嘗試編譯此代碼時:

#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”壓入堆棧以進行浮點運算?

我不知道有一種匯編語言支持立即使用的文字浮點常量。 通常的方法是聲明包含浮點常量的初始化存儲並引用它:

const1:     dq  1.2345
...
     fldl    const1

對於您給出的示例,可以更直接地執行此操作:

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

否則,這一定是一個人為的復雜項目,也許是功課。

嘗試這樣的事情

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

其中?????????的被雙常數的IEEE表示所取代。 這種方法的優點是它在正常和位置無關(PIC,即共享庫)代碼中同樣有效。

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 上游

復習: +表示io將用作輸入和 output。

在 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 上游

編譯並運行:

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等浮點指令,例如以下 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 上測試。

fld指令的唯一有效操作數是 memory 或浮點堆棧寄存器。

(此外,您已將y指定為asm塊的輸入操作數,而它應該是 output。將其限制為 memory ( "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;
}

您可以通過讓 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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM