Linux 如果浮点比较在内部是';是否与描述或记录的不一致?这是gdb的一个怪癖吗?
我一直在使用Richard Blum的专业汇编语言,它最初的浮点比较程序可以运行,但是,在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
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
和realfnstsw
。看见(在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 )