汇编:使用两个 fld、fcomp、fnstsw 和 test 41h 转换为 if 语句
Assembly: converting to if statement using two fld, fcomp, fnstsw and test 41h
有人可以帮助我理解以下代码吗?
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
表示(无效操作)或(堆栈错误)?
有关 x87 状态字的信息,请参阅 this page。
请注意,16 位状态字存储到ax
,但test
指令只查看高8 位(ah
)。所以 41h
匹配状态字的 C0
和 C3
位。在 ah
上使用 8 位测试可避免因使用 16 位 test
和 imm16
而降低 Intel CPU 速度。 (操作数大小前缀改变指令其余部分的长度,即所谓的长度改变前缀解码器停顿)。
fld / fcomp / fld / fnstsw
:我也觉得这很奇怪。我想知道目标是否是根据内存位置设置状态字中的非规范位,但是 C0
等等基于 fcomp
设置。 (这不是您得到的,因为 fld
未定义或设置 C0-3
。)
Intel 的 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 优化来避免 pop/reload 相同的值。
fld qword ptr [L1000F168]
fcomi qword ptr [L1000A2F0]
jna L100012F0 ; jump unless st(0) > [L1000A2F0]
我可能对其中一个比较有倒退的感觉,所以如果有什么不合理的地方,请仔细检查。
这段代码来自哪里?它是编译器输出吗?或者它可能是手写的 asm?
fcomp qword ptr [L1000A2F0] 将 stack[0] 与 L1000A2F0 中的值进行比较,并将其弹出到堆栈的末尾。
example
stack[0] = 50
[L1000A2F0] = 45
if (stack[0] > [L1000A2F0])
pop stack[0]; // (stack[7] = stack[0])
else
pop [L1000A2F0]; // (stack[7] = [L1000A2F0])
希望这对您有所帮助。
有人可以帮助我理解以下代码吗?
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
表示(无效操作)或(堆栈错误)?
有关 x87 状态字的信息,请参阅 this page。
请注意,16 位状态字存储到ax
,但test
指令只查看高8 位(ah
)。所以 41h
匹配状态字的 C0
和 C3
位。在 ah
上使用 8 位测试可避免因使用 16 位 test
和 imm16
而降低 Intel CPU 速度。 (操作数大小前缀改变指令其余部分的长度,即所谓的长度改变前缀解码器停顿)。
fld / fcomp / fld / fnstsw
:我也觉得这很奇怪。我想知道目标是否是根据内存位置设置状态字中的非规范位,但是 C0
等等基于 fcomp
设置。 (这不是您得到的,因为 fld
未定义或设置 C0-3
。)
Intel 的 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 优化来避免 pop/reload 相同的值。
fld qword ptr [L1000F168]
fcomi qword ptr [L1000A2F0]
jna L100012F0 ; jump unless st(0) > [L1000A2F0]
我可能对其中一个比较有倒退的感觉,所以如果有什么不合理的地方,请仔细检查。
这段代码来自哪里?它是编译器输出吗?或者它可能是手写的 asm?
fcomp qword ptr [L1000A2F0] 将 stack[0] 与 L1000A2F0 中的值进行比较,并将其弹出到堆栈的末尾。
example
stack[0] = 50
[L1000A2F0] = 45
if (stack[0] > [L1000A2F0])
pop stack[0]; // (stack[7] = stack[0])
else
pop [L1000A2F0]; // (stack[7] = [L1000A2F0])
希望这对您有所帮助。