Linux 如果浮点比较在内部是';是否与描述或记录的不一致?这是gdb的一个怪癖吗?

Linux 如果浮点比较在内部是';是否与描述或记录的不一致?这是gdb的一个怪癖吗?,linux,assembly,x86,gdb,x87,Linux,Assembly,X86,Gdb,X87,我一直在使用Richard Blum的专业汇编语言,它最初的浮点比较程序可以运行,但是,在Linux上运行gdb时,一些中间步骤出乎意料 试验: C3 C2 C0 1 0 0 -- Equal numbers case (behavior as described in the documentation) ----------------------------------------------- 1 1 0

我一直在使用Richard Blum的专业汇编语言,它最初的浮点比较程序可以运行,但是,在Linux上运行gdb时,一些中间步骤出乎意料

试验:


C3      C2      C0
1       0       0   -- Equal numbers case (behavior as described in the documentation)

-----------------------------------------------

1       1       0   -- Value1 < Value2, actual
    (SAHF acts as though it has a NOT applied before altering the flags)

(The status register itself seems to be the inverse of the expected:)
0       0       1   -- expected

-----------------------------------------------

1       0       0   -- Value1 > Value2

0       0       0   -- expected

(Output of SAHF contorts somehow to permit CF = ZF = 0 )
下面是程序(添加了我的注释,删除了dwarf调试中不需要的nop):

(如果有人想试一试的话,我还翻译了一个版本的nasm语法并运行了它——但我的快速测试似乎没有产生不同的结果。)

它的构建和链接:

as -o fcomtest.o fcomtest.s --32 --gdwarf-2
ld -o fcomtest fcomtest.o -m elf_i386
我使用的是以下gdb输入脚本(您可能需要在最后几行中添加或删除“step”命令,具体取决于设置的value1和value2以及采用的分支):

最后,为了检查调试器输出并轻松重现,我使用以下命令行:

$gdb-q-x gdb输入脚本>gdb.output fcomtest

然后,您可以通过以下方式看到大量输出:

$cat gdb.output

理论 在这些岗位上,有关于这一机制的讨论: , ,并在链接文章中

特别是,FCOM应将FPU堆栈的ST0值与另一个值进行比较,并根据以下内容更改FPU状态寄存器的C3、C2和C0代码位:

+-----------------+----+-----+----+
| Condition       | C3 |  C2 | C0 |
+-----------------+----+-----+----+
| ST0 > argument  | 0  |  0  | 0  |
| ST0 < argument  | 0  |  0  | 1  |
| ST0 = argument  | 1  |  0  | 0  |
+-----------------+----+-----+----+
我知道这有点长(但它显示了如何很容易地重建)总而言之:如果更改值1和2并重新编译,我发现实际上似乎发生了以下情况——至少在gnu调试器的输出中是这样:


C3      C2      C0
1       0       0   -- Equal numbers case (behavior as described in the documentation)

-----------------------------------------------

1       1       0   -- Value1 < Value2, actual
    (SAHF acts as though it has a NOT applied before altering the flags)

(The status register itself seems to be the inverse of the expected:)
0       0       1   -- expected

-----------------------------------------------

1       0       0   -- Value1 > Value2

0       0       0   -- expected

(Output of SAHF contorts somehow to permit CF = ZF = 0 )

C3 C2 C0
1 0 0—相等数字情况(行为如文档中所述)
-----------------------------------------------
10--值1<值2,实际值
(SAHF的行为就好像它在更改标志之前未应用)
(状态寄存器本身似乎与预期的相反:)
0 1--应为0
-----------------------------------------------
1 0 0--值1>值2
0--应为0
(SAHF的输出以某种方式扭曲,以允许CF=ZF=0)

我已经描述了如何复制它,所以它只是一个复制粘贴来查看结果。是否只是gdb的一些细节改变了C3、C2和C0的值,然后进行调整以使标志生效在所有情况下,最终都会选择正确的分支。。。我还没有尝试过(我没有练习过)其他调试器,以查看调试器是否只是为了value1而在中间步骤中出错!=值2个案例。

您的脚本开始执行
br\u start
run
step
打印/t$fstat
——这将在
flds值1
之后和
fcoms值2
之前为
$fstat code>,不是吗?[有了汇编程序,我对
stepi
si
)感觉更舒服,因为它是值得的。]如果在
打印之前向脚本添加
disass$pc,+1
,它将显示要执行的下一条指令。在
display/i$pc
gdb停止时,它将自动显示下一条要执行的指令——特别是在
si
@ChrisHall之后:注意
stepi
fstsw
视为两条单独的指令:
fwait
和real
fnstsw
。看见(在286或386及更高版本上,
fwait
是不相关的,但汇编程序仍然盲目地遵循定义的编码,包括
fwait
nop,即使是32位和64位代码)。OP是用asm源代码调试信息构建的,因此
step
将逐步完成整个过程,并可能使他们的航位推算工作正常。不过,使用
starti
相当于设置断点并使用
run
,可能更简单。如果我们不信任GDB的
p/x$eflags
,也许可以尝试
pushf
。我得到
$eflags=0x212
但是
p/x*(int*)$sp
sahf
/
pushf
之后是
0x312
。哦,第二个字节的低位是TF,我是单步交互的。但除此之外,它们是匹配的。@PeterCordes:谢谢你在
fwait
上提供的详细信息。我认为问题在于,
print/t$fstat
是在
fcoms
之前完成的,“航位推算”几乎从一开始就被取消了。@ChrisHall:IDK,我没有试着按照那个脚本来做。太乱了。我只是在GDB中以交互方式进行了尝试。我不确定我是否发现了任何不匹配的地方。我曾认为AF设置是一个惊喜,因为
pushf
的低位字节与
AH
不匹配,但我认为一旦考虑到
sahf
未设置的保留位,它就匹配正常了
0x38
屏蔽到
0x10
,EFLAGS中始终设置的位#1为
0x12
Case 4II (value1 +ve, value2 +ve; val1 greater magnitude, val2 lesser magnitude)

15      14      13      12      11      10      09      08  -- FPU status reg.
FPU     C3      SP      SP      SP      C2      C1      C0

07      06      05      04      03      02      01      00  -- AH register

1       1       1       0       0       0       0       0

[In this result of FCOM:  C3 has been set to 1 -- not what was expected.  The
expected result was C3 = 0, C2 = 0, C0 = 0]

SAHF instruction:
From the manual: 07 => SF, 06 => ZF, 04 => AF, 02 => PF, 00 => CF
From the textbook: 06 => ZF, 02 => PF, 00 => CF
Actual behavior: -07 => SF, -06 => ZF , -04 => AF, 02 => PF ?, 00 => CF ? ]

EFLAGS register:

0       0       0       0       0       0       1       0   -- Before SAHF

SF      ZF      -       AF      -       PF      -       CF

0       0       0       1       0       0       1       0   -- After SAHF

[Here, CF = 0 and ZF = 0, so the JA branch is taken and the result is as
desired]

C3      C2      C0
1       0       0   -- Equal numbers case (behavior as described in the documentation)

-----------------------------------------------

1       1       0   -- Value1 < Value2, actual
    (SAHF acts as though it has a NOT applied before altering the flags)

(The status register itself seems to be the inverse of the expected:)
0       0       1   -- expected

-----------------------------------------------

1       0       0   -- Value1 > Value2

0       0       0   -- expected

(Output of SAHF contorts somehow to permit CF = ZF = 0 )