Assembly 汇编:使用两个fld、fcomp、fnstsw和test 41h转换为if语句
有人能帮我理解下面的代码吗Assembly 汇编:使用两个fld、fcomp、fnstsw和test 41h转换为if语句,assembly,x86,disassembly,fpu,x87,Assembly,X86,Disassembly,Fpu,X87,有人能帮我理解下面的代码吗 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 L10001
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
进行比较?as41h
表示(无效操作)或(堆栈故障)有关x87状态字的信息,请参阅
请注意,16位状态字存储到ax
,但test
指令仅查看高位8位(ah
)。因此41h
匹配状态字的C0
和C3
位。在ah
上使用8位测试可以避免在英特尔CPU上使用带imm16
的16位test
时速度减慢。(操作数大小前缀更改指令其余部分的长度,即所谓的长度更改前缀解码器暂停)
fld/fcomp/fld/fnstsw
:我也觉得这很奇怪。我想知道这样做的目的是否是基于内存位置设置状态词中的非规范位,但基于fcomp
设置C0
,等等。(这不是您得到的结果,因为fld
使C0-3
未定义或设置。)
英特尔的insn参考手册说fld
未定义C0
和C3
,因此生成此代码的编译器取决于某些特定行为。如果没有fwait
,状态词可能不会从fcomp
更新?我还没有把整件事弄明白。我还没有找到(或努力寻找)关于何时需要旧CPU上的fwait
,何时不需要的解释。据我所知,你永远不会在P5或更高版本上这样做
无论如何,我认为这段代码的作用是:
if (! ([L1000F168] > [L1000A2F0]))
goto L100012F0;
测试不大于等于测试fcomp qword ptr[L1000A2F0]将堆栈[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])
希望这有帮助。这看起来像是反汇编程序的输出。感谢您的回复。它是编译器生成的可执行文件代码的一部分。正如您所说,它是一个
如果(值[L1000F168]>值[L1000A2F0])
?我理解对了吗?它是否依赖于以前加载到堆栈中的其他内容?顺便说一句,在此代码之前,堆栈没有比函数开始时更多的额外推送值。@RudyVelthuis:是的,我发现它是对二进制文件进行反向工程,但二进制文件可能是通过组装手工编写的asm创建的。我猜编译器不够聪明,无法使用fcom
并保存负载。(那时候,fld
没有将C0
和C3
保留为未定义。或者可能没有fwait
,在该点存储标志时是否从比较中获得了标志?@barej:我更新了我的答案以回答您的评论。它不依赖于以前的st(0)
,它只依赖于fld
的x86未定义行为不接触状态字中的某些位。AH包含AX的位8-15,因此它有状态字的位8-15$正如Peter Cordes所说,41对应于比特14=C3和比特8=C0。
fld qword ptr [L1000F168]
fcomi qword ptr [L1000A2F0]
jna L100012F0 ; jump unless st(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])