x86汇编程序:浮点比较

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.你的代码有fcomiFCOMI.(因为它是一个堆栈,它们被加载到),参考第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)

  • 非常令人印象深刻 优秀.一个小评论:`ja`的反面是`jbe`,而不是`jb`. (7认同)
  • @Ray Toal:你是对的.即使在这种情况下它没有任何区别,我改变了这个例子,因为它更有意义. (2认同)