第69部分- Linux x86 64位汇编 FPU之浮点条件分支

第69部分- Linux x86 64位汇编 FPU之浮点条件分支

浮点的比较不像整数那么容易,在处理整数时候,容易使用CMP指令并且评估EFLAGS寄存器中的值来确定是否大于,等于还是小于。

浮点数,不能使用CMP指令,FPU提供了一些自己的指令来比较浮点值。

FCOM比较指令

比较的结果设置在状态寄存器的C0,C2和C3条件代码位中。

需要使用FSTSW指令把状态寄存器的值复制到AX寄存器,然后使用test指令判断比较结果。

示例

.extern printf ;//调用外部的printf函数
.section .data
   fmtg: .asciz  "greate \n"
   fmtb: .asciz  " less \n"

value1:
   .float 100.923
value2:
   .float 400.5532
.section .text
.globl _start
_start:
   nop
   flds value1;//加载value1 10.923到st0
   fcoms value2;// st0和value2 4.5532对比。
   fstsw;//加载状态寄存器到AX
   sahf;//加载AH寄存器到EFLAGS中。
   ja greater;//大于则跳转到greater
   jb lessthan;//小于则跳转到lessthan
greater:
   movq $fmtg,%rdi
   call printf
   jmp exit

lessthan:
   movq $fmtb,%rdi
   call printf
exit:
   movq $60,%rax
   syscall

as -g -o fcomtest.o fcomtest_att.s

ld -o fcomtest fcomtest.o -lc -I /lib64/ld-linux-x86-64.so.2

这里有指令:

LAHF(加载状态标志位到 AH)指令将 EFLAGS 寄存器的低字节复制到 AH。

被复制的标志位包括:符号标志位、零标志位、辅助进位标志位、奇偶标志位和进位标志位。

SAHF(保存 AH 内容到状态标志位)指令将 AH 内容复制到 EFLAGS(或 RFLAGS)寄存器低字节。将AH寄存器的第0,2,4,6,7分别传送到进位、奇偶校验、对准、零和符号标志、不影响EFLAGS寄存器的其他位。

FSTSW和SAHF指令组合传送如下:

  • C0位传送到EFLAGS的进位标志
  • C2位传送到EFLAGS的奇偶校验标志
  • C3位传送到EFLAGS的零标志

为后续的JA,JB,JZ指令提供了很好的工作。

 

FCOMI指令

此外,还可以使用FSTSW和SAHF指令组合效果的指令,就是FCOMI。

只能比较FPU寄存器中的值,不能比较FPU寄存器和内存中的值。

FUCOMI和FUCOMP是确保被比较的值是合法的浮点数。

示例

.extern printf ;//调用外部的printf函数
.section .data
   fmtg: .asciz  "greate \n"
   fmtb: .asciz  " less \n"
value1:
   .float 10.923
value2:
   .float 4.5532
.section .text
.globl _start
_start:
   nop
   flds value2;//加载value2 4.5532到st0
   flds value1;//加载value1 10.923到st0
   fcomi %st(1), %st(0);//比较st1,st0
   ja greater
   jb lessthan

greater:
   movq $fmtg,%rdi
   call printf
   jmp exit

lessthan:
   movq $fmtb,%rdi
   call printf
exit:
   movq $60,%rax
   syscall

as -g -o fcomitest.o fcomitest_att.s

ld -o fcomitest fcomitest.o -lc -I /lib64/ld-linux-x86-64.so.2

 

FCMOV指令

类似整数的CMOV指令,FCMOV指令可以编写浮点值的条件传送。根据EFLAGS寄存器中的值,FCMOV系列的指令把FPU寄存器ST(x)中的源操作数传送到FPU寄存器ST(0)中目标操作数。如果条件为true,就把ST(x)寄存器中值传送到ST(0)寄存器。

常用的方法是在FCMOV之前使用FCOMI

格式是:

Fcmovx source, destination

其中source是ST(x)寄存器,destination是ST(0)寄存器。

示例

.extern printf ;//调用外部的printf函数
.section .data
   fmt: .ascii  "result is: %f \n"
value1:
   .float 20.5
value2:
   .float 10.90
.section .text
.globl _start
_start:
   nop
   finit
   flds value1;//加载value1 20.5到st0
   flds value2;//加载value2 10.90到st0,20.5移动到st1
   fcomi %st(1), %st(0);//如果st0小于st1,设置eflags,然后fcmovb会将st1值复制到st0.
   fcmovb %st(1), %st(0)

   fstl result;//加载结果到result
   movq $fmtb,%rdi
   movq result,%xmm0
   call printf
exit:
   movq $60,%rax
   syscall

as -g -o fcmovtest.o fcmovtest_att.s

ld -o fcmovtest fcmovtest.o -lc -I /lib64/ld-linux-x86-64.so.2

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值