x86汇编中的冲突符号:movsx然后是unsigned compare/branch?

ine*_*ero 3 x86 assembly masm micro-optimization signedness

我对以下代码段感到困惑:

movsx   ecx, [ebp+var_8] ; signed move
cmp     ecx, [ebp+arg_0]
jnb     short loc_401027 ; unsigned jump
Run Code Online (Sandbox Code Playgroud)

这似乎有冲突.Var_8似乎是在签名扩展帐户上签名的.然而,jnb暗示var_8未在帐户上签名,它是无符号的比较.

那么,var_8是签名还是未签名?那么arg_0呢?

ana*_*lyg 5

如Jester所述,无符号比较可用于对带符号数进行范围检查.例如,一个常见的C表达式,用于检查索引是否介于0和某个限制之间:

short idx = ...;
int limit = ...; // actually, it's called "arg_0" - is it a function's argument?
if (idx >= 0 && idx < limit)
{
    // do stuff
}
Run Code Online (Sandbox Code Playgroud)

这里idx,符号扩展后,是一个带符号的32位数字(int).这个想法是,在将它与limit未签名的情况进行比较时,它会同时进行两次比较.

  1. 如果idx是肯定的,那么"签名"或"无符号"无关紧要,因此无符号比较给出了正确的答案.
  2. 如果idx是否定的,那么将其解释为无符号数将产生一个非常大的数字(大于2 31 -1),因此在这种情况下,无符号比较也给出了正确的答案.

所以一个无符号的比较做了两个签名比较的工作.这仅在limit签名和非负面时有效.如果编译器可以证明它是非负的,它将生成这样的优化代码.


另一种可能性是,如果最初的C代码是错误的,并且它使用unsigned进行比较.C的一个有些令人惊讶的特性是当有符号变量与无符号变量进行比较时,效果是无符号比较.

short x = ...;
unsigned y = ...;

// Buggy code!
if (x < y) // has surprising behavior for e.g. x = -1
{
    // do stuff
}

if (x < (int)y) // better; still buggy if the casting could overflow
{
    // do stuff
}
Run Code Online (Sandbox Code Playgroud)