Jus*_*wer 15 floating-point x86 assembly compare gnu-assembler
作为编译器项目的一部分,我必须为x86编写GNU汇编代码来比较浮点值.我试图找到有关如何在线进行此操作的资源,据我所知,它的工作原理如下:
假设我要比较的值是浮点堆栈上的唯一值,那么fcomi
指令将比较这些值并设置CPU标志,以便je
可以使用...指令.
我问,因为这只会有效.例如:
.section .data
msg: .ascii "Hallo\n\0"
f1: .float 10.0
f2: .float 9.0
.globl main
.type main, @function
main:
flds f1
flds f2
fcomi
jg leb
pushl $msg
call printf
addl $4, %esp
leb:
pushl $0
call exit
Run Code Online (Sandbox Code Playgroud)
即使我认为应该打印"Hallo"也不会打印,如果你切换f1和f2,它仍然不会是一个逻辑上的矛盾.jne
并且jl
但是似乎做工精细.
我究竟做错了什么?
PS:fcomip只弹出一个值还是同时弹出?
use*_*653 38
这一切都来自Intel 64和IA-32架构软件开发人员手册的第2卷.
fstsw
只设置一些标志sahf
.你的代码有fcomi
和FCOMI
.(因为它是一个堆栈,它们被加载到),参考第2A卷第3-348页的表格,您可以看到这是"ST0 <ST(i)"的情况,因此它将清除ZF和PF并设置CF. 同时在pg.3-544卷 你可以读到2A,这CMP
意味着"如果更大则跳跃(ZF = 0和SF = OF)".换句话说,它正在测试符号,溢出和零标志,但%st(0) == 9
不设置符号或溢出!
根据您希望跳转的条件,您应该查看可能的比较结果并确定您想要跳转的时间.
+--------------------+---+---+---+ | Comparison results | Z | P | C | +--------------------+---+---+---+ | ST0 > ST(i) | 0 | 0 | 0 | | ST0 < ST(i) | 0 | 0 | 1 | | ST0 = ST(i) | 1 | 0 | 0 | | unordered | 1 | 1 | 1 | one or both operands were NaN. +--------------------+---+---+---+
我已经制作了这张小桌子,以便更容易理解:
+--------------+---+---+-----+------------------------------------+ | Test | Z | C | Jcc | Notes | +--------------+---+---+-----+------------------------------------+ | ST0 < ST(i) | X | 1 | JB | ZF will never be set when CF = 1 | | ST0 <= ST(i) | 1 | 1 | JBE | Either ZF or CF is ok | | ST0 == ST(i) | 1 | X | JE | CF will never be set in this case | | ST0 != ST(i) | 0 | X | JNE | | | ST0 >= ST(i) | X | 0 | JAE | As long as CF is clear we are good | | ST0 > ST(i) | 0 | 0 | JA | Both CF and ZF must be clear | +--------------+---+---+-----+------------------------------------+ Legend: X: don't care, 0: clear, 1: set
换句话说,条件代码与使用无符号比较的条件代码匹配.如果您正在使用,也是如此%st(1) == 10
.
如果(或两者)操作数JG
为NaN,则设置FCOMI
.(FP相比较有4个可能的结果:FMOVcc
,fcomi
,ZF=1 PF=1 CF=1
,或无序的).如果您关心您的代码对NaN的作用,您可能需要额外的>
或<
.但并非总是如此:例如,==
如果CF = 0且ZF = 0 ,则仅为真,因此在无序情况下不会采用它.如果您希望无序情况采用与下面相同的执行路径或相同,那么jp
就是您所需要的.
在这里你应该使用,jnp
如果你想要它打印(即.ja
),ja
如果你不想(对应JA
).(注意这可能有点令人困惑,因为如果我们不跳,我们只打印).
关于你的第二个问题:默认情况下if (!(f2 > f1)) { puts("hello"); }
不弹出任何东西.你想要它的近亲JBE
表演if (!(f2 <= f1)) { puts("hello"); }
.您应该在使用后始终清除fpu寄存器堆栈,因此假设您希望打印消息,所有程序中的所有程序都会像这样结束:
.section .rodata
msg: .ascii "Hallo\n\0"
f1: .float 10.0
f2: .float 9.0
.globl main
.type main, @function
main:
flds f1
flds f2
fcomip
fstp %st(0) # to clear stack
ja leb # won't jump, jbe will
pushl $msg
call printf
addl $4, %esp
leb:
pushl $0
call exit
Run Code Online (Sandbox Code Playgroud)