天天看點

第59部分- Linux x86 64位彙編内聯彙編使用浮點值第59部分- Linux x86 64位彙編内聯彙編使用浮點值

第59部分- Linux x86 64位彙編内聯彙編使用浮點值

FPU堆棧方式使用寄存器在内聯彙編中有一點差別。

内聯彙編中:

  • f引用任何可用的浮點寄存器
  • t引用頂部的浮點寄存器
  • u引用第二個浮點寄存器

在擷取輸出值的時候不能使用限制f,必須聲明限制t或者u來指定輸出值所在的fpu寄存器。

示例

#include <stdio.h>

int main()
{
   float angle = 90;
   float radian, cosine, sine;

   radian = angle / 180 * 3.14159;

   asm("fsincos";//求解sin和cos值,此時st0是radian值,結果存放于st0和st1
       :"=t"(cosine), "=u"(sine);//輸出是st0和st1
       :"0"(radian));

   printf("The cosine is %f, and the sine is %f\n", cosine, sine);
   return 0;
}
           

gcc -o sincostest sincostest.c

反彙編:

gcc -o sincostest.s -S sincostest.c

有代碼片段:

        flds    -20(%rbp)

#APP

# 11 "sincostest.c" 1

        fsincos

# 0 "" 2

#NO_APP

        fxch    %st(1)

        fstps   -20(%rbp)

        fstps   -8(%rbp)

先使用了flds加載,最後将st0和st1都通過fstps進行了彈出操作。保持了fpu寄存器的幹淨。

示例二

如果FPU堆棧執行的操作沒有被清除,就必須在改動的寄存器清單中指定适當的FPU寄存。

#include <stdio.h>

int main()
{
   int radius = 10;
   float area;

   asm("fild %1\n\t"
       "fimul %1\n\t"
       "fldpi\n\t"
       "fmul %%st(1), %%st(0)"
       : "=t"(area)
       :"m"(radius)
       : "%st(1)");

   printf("The result is %f\n", area);
   return 0;
}
           

gcc -o areatest areatest.c

把半徑值放在一個記憶體radius位置中,通過fild加載radius中到st0中。

然後将記憶體radius位置和st0相乘,存在st0中。加載π到st0中,原半徑相乘值移動到st1中。将st0和st1相乘。将st0結果複制給area變量。這裡我們看到st0作為了輸出寄存器使用,但是st1沒有在輸入和輸出中标記出來,是以需要在改動的寄存器清單中列出它。

繼續閱讀