在反汇编一个可执行文件时,我遇到了cmove指令。我已经在互联网上搜索过了,但我只发现这是一个有条件的移动,如果源和目的地相等,就会发生mov。我不明白的是为什么我需要它,因为它不改变操作数。它的目的是什么?
cmove
mov
gwo2fgha1#
CMOVcc指令不比较源和目标。它们使用来自先前比较(或设置标志的其他操作)的标志,其确定是否应该进行移动。(Intel manual)示例;如果eax和ebx相等,则将edx复制到ecx:
CMOVcc
eax
ebx
edx
ecx
cmp eax, ebx cmove ecx, edx
这与以下操作相同:
cmp eax, ebx jne skip mov ecx, edx skip:
uubf1zoe2#
cmov的目的是允许软件(在某些情况下)避免分支。例如,如果你有这样的代码:
cmov
cmp eax,ebx jne .l1 mov eax,edx .l1:
..,则当现代CPU看到jne分支时,它将猜测是否将采用该分支,然后基于该猜测开始推测性地执行指令。如果猜测是错误的,则会有性能损失,因为CPU必须丢弃任何推测性执行的工作,然后开始获取并执行正确的路径。对于有条件移动(例如cmove eax,edx),CPU不需要猜测将执行哪个代码,并且避免了错误预测分支的成本。然而,CPU无法知道eax中的值是否会更改,这意味着依赖于条件移动结果的后续指令必须等待,直到条件移动完成(而不是使用假定值进行推测性执行,并且不会停止)。这意味着,如果分支可以容易地预测,则分支可以更快;并且如果分支不能被容易地预测,则条件移动可以更快。请注意,条件移动从来不是严格需要的(它总是可以用分支来完成)-它更像是一个可选的优化。
jne
cmove eax,edx
jpfvwuh43#
我已经在互联网上搜索过了,但我只发现这是一个有条件的移动,如果源和目的地相等,就会发生移动。你的结论是不正确的。如果前一条指令以满足CMOVcc指令编码指定的条件的方式更改了CPU标志(CF、ZF、OF、SF),则会发生移动。指令名称中的cc后缀是条件代码的占位符,条件代码可以是A、AE、B、BE、C、E、G、GE、L、LE、NA、NAE、NB、NBE、NC、NE、NG、NGE、NL、NLE、NO、NP、NS、NZ、O、P、PE、PO、S和Z中的任何一个。在本例中,如果设置了零标志(ZF),CMOVE将执行从源到目标的移动。我不明白的是为什么我需要它,因为它不改变操作数。正如我上面解释的,如果满足条件,它确实会改变目的地。它的目的是什么?目的是帮助避免条件分支。避免条件分支的原因是CPU很难预测这些分支是否会被执行。考虑到x86架构是高度推测性和无序的,它将在它预测的分支开始解码和执行代码,因为在实际需要提高代码执行性能之前就已经采取了。如果后来发现分支预测不正确,CPU将不得不刷新执行管道并从头开始执行另一个代码路径。如果这种情况发生在循环或其他关键代码路径中,它会显著降低代码性能,因此您可以使用CMOVcc,以便尽可能避免条件分支。
cc
CMOVE
jc3wubiy4#
CMOVcc指令检查EFLAGS寄存器中的一个或多个状态标志(CF、OF、PF、SF和ZF)的状态,并且如果标志处于指定状态(或条件),则执行移动操作。条件码(cc)与每一指令相关联以指示正被测试的条件。如果不满足条件,则不执行移动,并且继续执行CMOVcc指令之后的指令。这些指令可以将16位或32位值从存储器移动到通用寄存器,或者从一个通用寄存器移动到另一个通用寄存器。不支持8位寄存器操作数的条件移动。术语“小于”和“大于”用于有符号整数的比较,术语“高于”和“低于”用于无符号整数。https://wiki.cheatengine.org/index.php?title=Assembler:Commands:CMOVE
4条答案
按热度按时间gwo2fgha1#
CMOVcc
指令不比较源和目标。它们使用来自先前比较(或设置标志的其他操作)的标志,其确定是否应该进行移动。(Intel manual)示例;如果
eax
和ebx
相等,则将edx
复制到ecx
:这与以下操作相同:
uubf1zoe2#
cmov
的目的是允许软件(在某些情况下)避免分支。例如,如果你有这样的代码:
..,则当现代CPU看到
jne
分支时,它将猜测是否将采用该分支,然后基于该猜测开始推测性地执行指令。如果猜测是错误的,则会有性能损失,因为CPU必须丢弃任何推测性执行的工作,然后开始获取并执行正确的路径。对于有条件移动(例如
cmove eax,edx
),CPU不需要猜测将执行哪个代码,并且避免了错误预测分支的成本。然而,CPU无法知道eax
中的值是否会更改,这意味着依赖于条件移动结果的后续指令必须等待,直到条件移动完成(而不是使用假定值进行推测性执行,并且不会停止)。这意味着,如果分支可以容易地预测,则分支可以更快;并且如果分支不能被容易地预测,则条件移动可以更快。
请注意,条件移动从来不是严格需要的(它总是可以用分支来完成)-它更像是一个可选的优化。
jpfvwuh43#
我已经在互联网上搜索过了,但我只发现这是一个有条件的移动,如果源和目的地相等,就会发生移动。
你的结论是不正确的。
如果前一条指令以满足
CMOVcc
指令编码指定的条件的方式更改了CPU标志(CF、ZF、OF、SF),则会发生移动。指令名称中的
cc
后缀是条件代码的占位符,条件代码可以是A、AE、B、BE、C、E、G、GE、L、LE、NA、NAE、NB、NBE、NC、NE、NG、NGE、NL、NLE、NO、NP、NS、NZ、O、P、PE、PO、S和Z中的任何一个。在本例中,如果设置了零标志(ZF),
CMOVE
将执行从源到目标的移动。我不明白的是为什么我需要它,因为它不改变操作数。
正如我上面解释的,如果满足条件,它确实会改变目的地。
它的目的是什么?
目的是帮助避免条件分支。
避免条件分支的原因是CPU很难预测这些分支是否会被执行。
考虑到x86架构是高度推测性和无序的,它将在它预测的分支开始解码和执行代码,因为在实际需要提高代码执行性能之前就已经采取了。
如果后来发现分支预测不正确,CPU将不得不刷新执行管道并从头开始执行另一个代码路径。
如果这种情况发生在循环或其他关键代码路径中,它会显著降低代码性能,因此您可以使用
CMOVcc
,以便尽可能避免条件分支。jc3wubiy4#
CMOVcc指令检查EFLAGS寄存器中的一个或多个状态标志(CF、OF、PF、SF和ZF)的状态,并且如果标志处于指定状态(或条件),则执行移动操作。条件码(cc)与每一指令相关联以指示正被测试的条件。如果不满足条件,则不执行移动,并且继续执行CMOVcc指令之后的指令。
这些指令可以将16位或32位值从存储器移动到通用寄存器,或者从一个通用寄存器移动到另一个通用寄存器。不支持8位寄存器操作数的条件移动。
术语“小于”和“大于”用于有符号整数的比较,术语“高于”和“低于”用于无符号整数。
https://wiki.cheatengine.org/index.php?title=Assembler:Commands:CMOVE