【问题标题】:Assembly comparison flags understanding装配比较标志理解
【发布时间】:2012-12-31 11:36:34
【问题描述】:

我很难理解汇编程序中的以下代码 sn-p:

if ( EAX >= 5 )
  EBX = 1;
else
  EBX = 2;"

在汇编程序中,这可以写成如下(根据我的书),模拟您通常在“更简单”的分支中使用的jge instruction,它一次只查看一个标志:

1     cmp eax, 5       ;(assuming eax is signed)
2     js signon        ;goto signon if SF = 1
3     jo elseblock     ;goto elseblock if OF = 1 and SF = 0
4     jmp thenblock    ;goto thenblock if SF = 0 and OF = 0
5 signon:
6     jo thenblock     ;goto thenblock if SF = 1 and OF = 1
7 elseblock:
8     mov ebx, 2
9     jmp next
10 thenblock:
11    mov ebx, 1
12    next:

我可以理解生成的标志可以是:(if (EAX >= 5)):

SF = 0 & OF = 0 但我无法理解标志是如何出现的: SF = 1 & OF = 1?这是什么计算得出的?

澄清我的意思:

如果 eax 处于负数下限,它可能会通过减 5 溢出到正数。如果它在正数上限,它不能通过减 5 溢出到负数?

【问题讨论】:

  • 是的,我明白了,但是 eax 怎么会溢出成负数呢?我可以理解 SF = 0 & OF = 1 如何不满足条件,但不知道 SF = 1 & OF = 1 如何满足。
  • 您正在阅读什么书/文档/网站? SF = 1 表示结果为负,OF = 1 表示操作导致带符号操作数的上溢/下溢。如果它们都设置了,则意味着左操作数是一个大的正数,而右操作数是一个小的负数,足以导致结果从正数翻转到负数。当第二个操作数为 5 时,这是不可能的。(编辑:在我看来,学习这个的最好的书是 Reversing - Secrets of Reverse Engineering。)
  • 这是什么书?当一个简单的jge 会做同样的事情并且更具可读性时,为什么要为多个条件分支所困扰?我认为整个 js/jo/jmp/jo 块是从通用解决方案中复制粘贴的,而无需费心将其适应特定上下文。
  • 这本书是每日 WTF 吗?那是可怕的代码,我希望这只是一个奇怪的例子,我从来没有在任何地方的生产环境中遇到过这样的事情!

标签: assembly x86 eflags


【解决方案1】:

用 3 位数字来考虑这些要容易得多,它们都是可伸缩的。嗯,如果这是签名的(您没有在高级代码中指定/发布),那么四位更好,因为您使用了 5。遍历 5 附近的数字(这显示了 alu 的输出)

cmp reg,5
0111 - 0101 = 0111 + 1010 + 1 = 10010
0110 - 0101 = 0110 + 1010 + 1 = 10001
0101 - 0101 = 0101 + 1010 + 1 = 10000
0100 - 0101 = 0100 + 1010 + 1 = 01111
0011 - 0101 = 0011 + 1010 + 1 = 01110

现在您必须了解硬件的工作原理。某些处理器系列在执行减法运算时会反转来自 alu 的进位标志,而其他处理器系列则不会。无论哪种方式,您都可以在 5 - 5 点看到状态变化。而且你这里也不需要进位标志,代码不使用它。

如果您正在做有符号数学,那么也可以尝试一些负数。

0000 - 0101 = 0000 + 1010 + 1 = 01011  
1111 - 0101 = 1111 + 1010 + 1 = 11010
1110 = 0101 = 1110 + 1010 + 1 = 11001

这可以说明问题。

有符号溢出定义为进位不等于加法器的 msbit 上的进位。这可能会变得混乱,所以我们只需要知道边界在哪里。

0111 - 0101 = 7 - 5 = 2
0110 - 0101 = 6 - 5 = 1
0101 - 0101 = 5 - 5 = 0
0100 - 0101 = 4 - 5 = -1
0011 - 0101 = 3 - 5 = -2

等等。使用这个 4 位模型,在有符号解释中,我们被限制为 +7 (0b0111) 到 -8 (0b1000)。所以 -3 - 5 之后我们会遇到麻烦:

1110 - 0101 = 1110 + 1010 + 1 = 11001 , -2 - 5 = -7
1101 - 0101 = 1101 + 1010 + 1 = 11000 , -3 - 5 = -8
1100 - 0101 = 1100 + 1010 + 1 = 10111 , -4 - 5 = 7 (-9 if we had more bits)
1011 - 0101 = 1011 + 1010 + 1 = 10110 , -5 - 5 = 6 (-10 if we had more bits)
1010 - 0101 = 1010 + 1010 + 1 = 10101 , -6 - 5 = 5 (-11 if we had more bits)
1001 - 0101 = 1001 + 1010 + 1 = 10100 , -7 - 5 = 4 (-12 if we had more bits)
1000 - 0101 = 1000 + 1010 + 1 = 10011 , -8 - 5 = 3 (-13 if we had more bits)

后五个是有符号溢出,有符号结果不能用可用位数表示。 (请记住,我们现在使用的是四位系统,最高位是进位位,当您查看结果时可以将其移除)。

签名标志只是结果的毫秒位,这也改变了有趣的边界。设置有符号标志(结果的毫秒位)的情况是低于 5 的正 (eax) 值和不导致有符号溢出的负数(+4 到 -3)。所有这些都在

因此,如果您通过 js 登录失败,则符号位关闭,即大于或等于 5 的数字(希望结果为 1)或结果为负数足以导致有符号溢出(希望结果为 2)。所以 jo elseblock 通过提取 2 个案例的结果(有符号溢出,非常否定)来对这两个案例进行排序。 jmp thenblock 取 5 以上的正数。

在我看来,您正在这里进行有符号数学运算(使用有符号溢出标志有点明显)。由于您使用 5 来比较和签名数学,因此您的系统中需要 4 位或更多位来实现此代码,因此 8、32、64、123456 位,它与 4 位系统的工作方式相同并不重要(对于这个比较)。我发现最小化位数来进行分析更容易。像这样的硬编码比较使它变得容易得多,就像上面、at和下面的手工计算结果一样。然后遍历有符号数的全零(零)到全一(减一),并且非常负数进入有符号溢出范围。对于无符号数字,它会更容易一些,但过程相同。

【讨论】:

  • 嗨!在研究了你的答案后,我有一些问题。首先不应该是“后五个是有符号溢出”而不是“后两个......”我的另一个问题是关于符号标志。你说符号标志只是结果的毫秒位。在您的回答中,您说在
  • 感谢您发现这些错误,现在有意义还是我的答案仍然有错误?
  • 非常感谢您更新@dwelch。你真的帮了我这个忙!
【解决方案2】:

如果 (EAX >= 5 ) EBX = 1; 别的 EBX = 2;"

cmp eax,5
jae biggerthan
mov ebx,2
jmp out
.biggerthan
mov ebx,1
.out

【讨论】:

    猜你喜欢
    • 2022-01-10
    • 2012-04-05
    • 2011-04-11
    • 2022-07-11
    • 1970-01-01
    • 1970-01-01
    • 2019-07-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多