第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没有在输入和输出中标记出来,所以需要在改动的寄存器列表中列出它。