有人可以帮助我理解以下代码吗?
fld qword ptr [L1000F168]
fcomp qword ptr [L1000A2F0]
fld qword ptr [L1000F168]
fnstsw ax
test ah,41h
jnz L100012F0
它是从执行代码转换为程序集的编译器的输出。
到目前为止我所知道的是
if(value[L1000F168] != value[L1000A2F0])
continue following
else
goto L100012F0
我说错了吗?
我不明白为什么[L1000F168]
被加载两次以及为什么ah
与41h
进行比较?因为41h
表示(无效操作)或(堆栈错误)?
答案 0 :(得分:1)
有关x87状态字的信息,请参阅this page。
请注意,16位状态字存储在ax
,但test
指令仅查看高8位(ah
)。因此41h
匹配状态字的C0
和C3
位。在ah
上使用8位测试可以避免因使用带有test
的16位imm16
而导致英特尔CPU速度减慢。 (操作数大小前缀改变指令其余部分的长度,即所谓的长度改变前缀解码器停止)。
fld / fcomp / fld / fnstsw
:这对我来说也很奇怪。我想知道目标是基于内存位置来处理状态字集中的非正常位,而是基于C0
设置fcomp
等等。 (这不是你得到的,因为fld
使C0-3
未定义或设置。)
英特尔的insn参考手册说fld
未定义C0
和C3
,因此生成此代码的编译器取决于某些特定行为。也许没有fwait
,状态字也不会从fcomp
更新?我还没有弄清楚整个fwait
的事情。我还没有找到(或者看起来很难)解释你何时需要fwait
旧CPU,以及什么时候没有。据我了解,你从未在P5或更高版本上做过。
无论如何,我认为这段代码的作用是什么:
if (! ([L1000F168] > [L1000A2F0]))
goto L100012F0;
测试不大于测试<=
或无序测试。这假设fld
实际上并未修改C0
和C3
。也许手册只说它没有定义,因为它可以在加载非正规或其他条件时设置它们?或者它在目前的芯片中根本不存在。或者它可能是英特尔手册中的另一个错误,实际上这已经很好了。或许这段代码不再适用了!最好用调试器测试它。
我认为一种更合理的方式来获得程序员可能希望的结果
fld qword ptr [L1000F168]
fcom qword ptr [L1000A2F0]
fnstsw ax
test ah,41h ; C0|C3: both zero iff st(0) > [L1000A2F0]
jnz L100012F0
由于OP说代码是编译器输出,我想这意味着它没有很好的x87优化来避免弹出/重新加载相同的值。
fld qword ptr [L1000F168]
fcomi qword ptr [L1000A2F0]
jna L100012F0 ; jump unless st(0) > [L1000A2F0]
我可能有一种向后比较的感觉,所以如果某些事情没有意义,请仔细检查。
这段代码是什么来的?是编译输出吗?或者它可能是手写的asm?