第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沒有在輸入和輸出中标記出來,是以需要在改動的寄存器清單中列出它。