【发布时间】:2017-04-23 05:59:19
【问题描述】:
我正在分析一系列x86 指令,并且对以下代码感到困惑:
135328495: sbb edx, edx
135328497: neg edx
135328499: test edx, edx
135328503: jz 0x810f31c
我知道sbb 等于des = des - (src + CF),换句话说,第一条指令以某种方式将-CF 放入edx。然后把negtive-CF变成CF,testCF是否等于0??
但请注意,jz 检查标志 ZF,而不是 CF!那么基本上上面的代码序列试图做什么?这是一个合法的x86指令序列,由g++版本4.6.3产生。
C++ 代码实际上来自botan 项目。您可以在here 找到整个汇编代码(Botan RSA 解密示例)。反汇编代码中有不少这样的指令序列。
【问题讨论】:
-
这来自什么来源?什么编译选项? (启用优化?任何
-mtune=bdver2或什么?AMD CPU 将sbb same,same识别为独立于 reg 的旧值,并且仅取决于 CF。在 Intel CPU 上,setc dl/ @987654346 可能会更快@(或者更好,have edx zeroed before running setc, preferably with a recognizes zeroing idiom to avoid a partial-register stall),所以我很惊讶 g++ 会将此序列用于任何事情。)它使用 TEST 很奇怪,因为 NEG 已经设置了标志。 -
sbb/neg是一个非常常见的 MSVC 习惯用法,用于生成无分支代码,但我通常不会看到 GCC 使用它——正如 Peter 建议的那样,它往往更喜欢setc。但是,无论哪种方式,由于这不是无分支代码,因此避免jc的扭曲没有多大意义。在我看来,test指令也是多余的。您说代码来自 GCC 4.6.3,但是 input 代码是从哪里来的?你有原始的 C 或 C++ 源代码,还是你在反编译一个不透明的二进制文件? -
我很想看看
g++是如何产生这个以及何时产生的,因为该代码看起来不太好,而经过优化的 g++ 通常会产生更好的东西。这看起来更像是一些人为构建的序列。 -
@PeterCordes 我可以让 GCC 4.6.4 用一个有点做作的例子来生成这个序列:godbolt.org/g/K2rUPv
-
@PeterCordes 我不认为 GCC 曾经使用过 SBB/NEG 习语,NEG 只是因为代码中的明确否定(使它有点做作)而存在。 GCC 使用刚刚使用 SBB 计算
e = a > b ? 0 : -1,然后 NEG 计算e = -e。如果将其简化为e = a > b ? 0 : 1或只是e = a > b,则 GCC 4.6.4 使用 SETcc 指令。顺便提一句。现代版本的 GCC 在某些情况下仍将使用 SBB,例如a > b ? 1 : 10。
标签: assembly x86 cpu-registers carryflag eflags