我有一些在Release版本中编译的未知C++代码,因此它已经过优化.我正在努力的一点是:
xor al, al
add esp, 8
cmp byte ptr [ebp+userinput], 31h
movzx eax, al
Run Code Online (Sandbox Code Playgroud)
这是我的理解:
xor al, al ; set eax to 0x??????00 (clear last byte)
add esp, 8 ; for some unclear reason, set the stack pointer higher
cmp byte ptr [ebp+userinput], 31h ; set zero flag if user input was "1"
movzx eax, al ; set eax to AL and extend with zeros, so eax = 0x000000??
Run Code Online (Sandbox Code Playgroud)
我不关心第2行和第3行.由于流水线的原因,它们可能按此顺序存在,而恕我直言与EAX无关.
但是,我不明白为什么我会首先清除AL,以便稍后清除EAX的其余部分.结果将恕我直言EAX = 0,所以这也可能
xor eax, eax
Run Code Online (Sandbox Code Playgroud)
代替.这段代码的优势或"优化"是什么?
一些背景信息:
我稍后会得到源代码.这是一个简短的C++控制台演示程序,可能只有20行代码,所以我称之为"复杂"代码.IDA在该程序中显示单个循环,但不包括此部分.Stud_PE签名扫描没有找到任何内容,但可能是Visual Studio 2013或2015编译器.
xor al,al已经比xor eax,eax大多数 CPU 慢了。例如,在 Haswell/Skylake 上,它需要 ALU uop 并且不会破坏对eax/rax旧值的依赖。对于 AMD CPU 或 Atom/Silvermont 来说,情况同样糟糕。(好吧,也许不一样,因为 AMD 没有消除xor eax,eax问题/重命名,但它仍然有一个错误的依赖关系,可以使用eax最后使用的任何内容序列化新的依赖关系链)。
al在与寄存器的其余部分分开重命名的CPU (Intel pre-IvyBridge)上,xor al,al可能仍被识别为归零习惯用法,但除非您主动想要保留寄存器的高字节,否则最好的归零方法al是xor eax,eax。
movzx除此之外,这样做只会让事情变得更糟。
我猜你的编译器不知何故感到困惑,并决定它需要一个 1 字节零,但后来意识到它需要将其提升到 32 位。 xor设置标志,因此它不能在后xor进行归零,并且它没有注意到它可能在 之前进行了异或归零。cmpeaxcmp
或者是这样,或者类似于 Jester 的建议,其中movzx是分支目标。即使是这种情况,xor eax,eax仍然会更好,因为在此代码路径上无条件地进行到 eax 的零扩展。
我很好奇哪个编译器从什么来源生成了这个。
| 归档时间: |
|
| 查看次数: |
593 次 |
| 最近记录: |