Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 汇编:使用两个fld、fcomp、fnstsw和test 41h转换为if语句_Assembly_X86_Disassembly_Fpu_X87 - Fatal编程技术网

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
进行比较?as
41h
表示(无效操作)或(堆栈故障)

有关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])