nasm 比较浮点值

nasm compare floating point values

我已经尝试了几个小时了,但我不明白为什么它不起作用。这是我使用的代码 never 进入 sort.swap.

sort:
  ; ...
.inner1
  ; load data[i] into st0
.inner2
  ; load data[j] into st0, data[i] now in st1
.test:
  fcomi      ; compare st0 (data[j]) with st1 (data[i]), status on cpu
  fcom       ; the same, but on the fpu status flag (just to compare in GDB)
  jl .swap
  ffreep st0 ; pop st0 (data[j])
  jmp .inner2
.swap:
  ; ...

在 GDB 中我这样做

b sort.test
r
si   // fcomi
si   // fcom
i float
i r

示例输出 1

我认为这个行为符合预期,因为 0.5327 小于 0.5262,因此它不应该去 sort.swap

(gdb) b sort.test
Breakpoint 1 at 0x804881b
(gdb) r
Starting program: /home/niklas/Desktop/erapraktikum/ss15-g52/Projekt1/Implementierung/build/read -v ../Testdaten/zufall-100.txt
Reading from input files ../Testdaten/zufall-100.txt ...
Read 100 entries.
calc.asm: calc(100, 0x804c170, 0x804d178, 0x804e180, 0x804f188)

Breakpoint 1, 0x0804881b in sort.test ()
(gdb) si
0x0804881d in sort.test ()
(gdb) si
0x0804881f in sort.test ()
(gdb) disass
Dump of assembler code for function sort.test:
   0x0804881b <+0>:     fcom   %st(1)
   0x0804881d <+2>:     fcomi  %st(1),%st
=> 0x0804881f <+4>:     jl     0x8048825 <sort.swap>
   0x08048821 <+6>:     ffreep %st(1)
   0x08048823 <+8>:     jmp    0x8048801 <sort.inner2>
End of assembler dump.
(gdb) i float
  R7: Valid   0x3ffe86b87e0000000000 +0,5262526273727416992     
=>R6: Valid   0x3ffe8862d40000000000 +0,5327579975128173828     
  R5: Empty   0x00000000000000000000
  R4: Empty   0x00000000000000000000
  R3: Empty   0x00000000000000000000
  R2: Empty   0x00000000000000000000
  R1: Empty   0x00000000000000000000
  R0: Empty   0x00000000000000000000

Status Word:         0x3020                  PE                        
                       TOP: 6
Control Word:        0x037f   IM DM ZM OM UM PM
                       PC: Extended Precision (64-bits)
                       RC: Round to nearest
Tag Word:            0x0fff
Instruction Pointer: 0x00:0x0804881d
Operand Pointer:     0x00:0x0804e184
Opcode:              0x0000
(gdb) i r
eax            0x804e184        134537604
ecx            0x1      1
edx            0x0      0
ebx            0x5573e000       1433657344
esp            0xffffc868       0xffffc868
ebp            0xffffc878       0xffffc878
esi            0x804e30c        134537996
edi            0x0      0
eip            0x804881f        0x804881f <sort.test+4>
eflags         0x202    [ IF ]
cs             0x23     35
ss             0x2b     43
ds             0x2b     43
es             0x2b     43
fs             0x0      0
gs             0x63     99
(gdb) si
0x08048821 in sort.test ()
(gdb) disass
Dump of assembler code for function sort.test:
   0x0804881b <+0>:     fcom   %st(1)
   0x0804881d <+2>:     fcomi  %st(1),%st
   0x0804881f <+4>:     jl     0x8048825 <sort.swap>
=> 0x08048821 <+6>:     ffreep %st(1)
   0x08048823 <+8>:     jmp    0x8048801 <sort.inner2>
End of assembler dump.

示例输出 2

然而,在这里,我希望跳入 sort.swap,因为 0.4657 小于 0.5262。但事实并非如此。

(gdb) disass
Dump of assembler code for function sort.test:
=> 0x0804881b <+0>:     fcom   %st(1)
   0x0804881d <+2>:     fcomi  %st(1),%st
   0x0804881f <+4>:     jl     0x8048825 <sort.swap>
   0x08048821 <+6>:     ffreep %st(0)
   0x08048823 <+8>:     jmp    0x8048801 <sort.inner2>
End of assembler dump.
(gdb) si
0x0804881d in sort.test ()
(gdb) 
0x0804881f in sort.test ()
(gdb) i float
  R7: Valid   0x3ffe86b87e0000000000 +0,5262526273727416992     
=>R6: Valid   0x3ffdee7c3c0000000000 +0,4657915830612182617     
  R5: Empty   0x00000000000000000000
  R4: Empty   0x00000000000000000000
  R3: Empty   0x00000000000000000000
  R2: Empty   0x00000000000000000000
  R1: Empty   0x00000000000000000000
  R0: Empty   0x00000000000000000000

Status Word:         0x3120                  PE             C0         
                       TOP: 6
Control Word:        0x037f   IM DM ZM OM UM PM
                       PC: Extended Precision (64-bits)
                       RC: Round to nearest
Tag Word:            0x0fff
Instruction Pointer: 0x00:0x0804881d
Operand Pointer:     0x00:0x0804e188
Opcode:              0x0000
(gdb) i r
eax            0x804e188        134537608
ecx            0x2      2
edx            0x0      0
ebx            0x5573e000       1433657344
esp            0xffffc868       0xffffc868
ebp            0xffffc878       0xffffc878
esi            0x804e30c        134537996
edi            0x0      0
eip            0x804881f        0x804881f <sort.test+4>
eflags         0x203    [ CF IF ]
cs             0x23     35
ss             0x2b     43
ds             0x2b     43
es             0x2b     43
fs             0x0      0
gs             0x63     99
(gdb) si
0x08048821 in sort.test ()
(gdb) 
0x08048823 in sort.test ()
(gdb) disass
Dump of assembler code for function sort.test:
   0x0804881b <+0>:     fcom   %st(1)
   0x0804881d <+2>:     fcomi  %st(1),%st
   0x0804881f <+4>:     jl     0x8048825 <sort.swap>
   0x08048821 <+6>:     ffreep %st(0)
=> 0x08048823 <+8>:     jmp    0x8048801 <sort.inner2>
End of assembler dump.

这是什么原因,我该如何让它发挥作用?谢谢!

来自 Intel's manual 第 2 卷 Jcc 的描述:

JL rel8   Jump short if less (SF≠ OF).

并且根据 FCOMI 的描述:

Performs an unordered comparison of the contents of registers ST(0) and ST(i) and sets the status flags ZF, PF, and CF in the EFLAGS register according to the result.

The FCOMI/FCOMIP and FUCOMI/FUCOMIP instructions set the OF, SF and AF flags to zero in the EFLAGS register

因此,SFFCOMI 之后将始终等于 OF,因此永远不会满足 JL 跳转的条件。


根据Table 3-31在FCOMI的描述你可以使用jc跳转如果ST(0) < ST(i)(或jb,这是jc 的不同名称)。