简体   繁体   English

为什么CMP(比较)有时会在8086汇编中设置进位标志?

[英]Why does CMP (compare) sometimes sets a Carry Flag in 8086 assembly?

I've been reading around and with the 8086 Instruction Set, it says that a CMP (compare) can set the Carry Flag. 我一直在阅读并使用8086指令集,它说CMP(比较)可以设置进位标志。 I understand that a compare subtracts two operands but I was wondering if anyone can provide an example when that is the case. 我知道比较会减去两个操作数,但我想知道是否有人可以在这种情况下提供一个例子。

I just can't grasp the idea of adding a number and a negative number will set the carry flag. 我只是无法掌握添加数字和负数的想法会设置进位标志。 I've read into the borrow flag but I just needed an example to clarify my understanding of a compare instruction. 我已经阅读了借旗,但我只需要一个例子来澄清我对比较指令的理解。

Also, I understand that if 3 - 5 = -2 would set the negative flag... when is carry set? 另外,据我所知,如果3 - 5 = -2会设置负标志...何时进位?

  • The carry flag is set after an operation that resulted in an underflow or overflow. 进位标志在导致下溢或溢出的操作之后设置。 For example, subtracting 10 from 6 will result in an underflow and set the carry flag. 例如,从6减去10将导致下溢并设置进位标志。 Similarly, adding 1 to the maximum value of the register will result in an overflow and set the carry flag. 类似地,将1添加到寄存器的最大值将导致溢出并设置进位标志。
  • The carry flag is also modified during a shift operation, it is set to the value of the last bit shifted out of the destination register. 进位标志也在移位操作期间被修改,它被设置为从目标寄存器移出的最后一位的值。
  • Bit testing will place the value of the tested bit into the carry flag. 位测试将测试位的值放入进位标志。 Opcodes that do this: BT, BTC, BTR, and BTS. 执行此操作的操作码:BT,BTC,BTR和BTS。
  • Instructions that affect the Carry Flag directly: CLC, CMC, and STC. 直接影响Carry Flag的说明:CLC,CMC和STC。
  • During a comparison, the carry flag is set just as if the two operands had been subtracted. 在比较期间,进位标志被设置,就好像已经减去了两个操作数一样。
  • During a negation (NEG), the carry flag is set unless the operand is zero, in which case it is cleared. 在否定(NEG)期间,除非操作数为零,否则设置进位标志,在这种情况下它被清除。

Carry flag is normally set when using unsigned arithmetic. 通常在使用无符号算术时设置进位标志。 For example, adding two unsigned (whose result does not fit in register) numbers would not raise the overflow flag but only carry flag. 例如,添加两个无符号(其结果不适合寄存器)数字不会引发溢出标志但只携带标志。 However, when using signed arithmetic, overflow flag is set in such event. 但是,使用带符号算术时,会在这种情况下设置溢出标志。

You can find examples of when the carry and overflow flags are set to 0 and 1 following addition or subtraction of integer numbers in this answer to a related question. 您可以在相关问题的答案中找到有关何时将进位和溢出标志设置为0和1的示例,其中加上或减去整数。
You can also find there sample C code emulating the add with carry and subtract with borrow instructions for 8-bit numbers and you can play with that, maybe get more examples. 你也可以找到样本C代码,用8位数字的借位指令模拟带有进位和减法的加法,你可以使用它,也许可以得到更多的例子。

The output format there is something like this: 输出格式有这样的:
127( 127) - 255( -1) - 1 = 127( 127) CY=1 OV=0
Where each number is represented as both unsigned and parenthesized signed (2's complement) next to it. 其中每个数字都表示为无符号和带括号的括号(2的补码)。 The number before = is the carry flag before ADC/SBB. =之前的数字是ADC / SBB之前的进位标志。 CY= and OV= show the carry and overflow flags after ADC/SBB. CY=OV=显示AD​​C / SBB后的进位和溢出标志。

Compare does pretty much the same thing as subtract without borrow, except it only affects the carry, overflow, sign and zero flags (and parity and auxiliary carry, but they're unimportant here) without modifying any number in a register/memory. 比较与没有借位的减法几乎完全相同,除了它只影响进位,溢出,符号和零标志(以及奇偶校验和辅助进位,但它们在这里不重要)而不修改寄存器/存储器中的任何数字。

https://www.hellboundhackers.org/articles/read-article.php?article_id=729 https://www.hellboundhackers.org/articles/read-article.php?article_id=729

Just as a quick summary, I wrote this article for two purposes. 就像快速总结一样,我写这篇文章有两个目的。 First, It is interesting, and more knowledge of how your computer works is always helpful. 首先,它很有趣,而且对计算机工作原理的更多了解总是有帮助的。 Secondly, there are always programs where flags will be manipulated directly, and it is helpful to know the effects they will have on jumps. 其次,总会有程序直接操作标志,并且知道它们对跳跃的影响是有帮助的。 For example, something as simple as CMP eax,ebx JC somewhere might confuse most beginning reversers, but hopefully not after this article. 例如,一些像CMP eax,ebx JC这样简单的东西可能会混淆大多数开始的反向器,但希望不会在本文之后。 Enjoy :) 请享用 :)

[Important Note: I will use 8 bit integers for my examples when I write out binary numbers. [重要说明:当我写出二进制数字时,我将使用8位整数作为我的例子。 Just remember that, although 8 bit integers are not commonly used in programming, the same rules that I discuss apply to integers with more bits] 请记住,尽管编程中不常用8位整数,但我讨论的相同规则适用于具有更多位的整数]

The CMP Instruction: CMP指令:

The CMP instruction operates by performing an implied subtraction of the two operands. CMP指令通过执行两个操作数的隐含减法来操作。 This means that the result is not stored in memory. 这意味着结果不会存储在内存中。 After subtracting them, it does a few quick tests, updating the Z,O,C,S, and P flags. 减去它们之后,它会做一些快速测试,更新Z,O,C,S和P标志。 The P, or parity, flag is rarely used, so we'll ignore it in this article for the purpose of brevity. P或奇偶校验标志很少使用,因此为了简洁起见,我们将在本文中忽略它。

Binary subtraction is performed by adding the negated version of the second operand from the first. 通过从第一个操作数添加第二个操作数的否定版本来执行二进制减法。 This is just like what you learned in middle school, about how 4+3 = 4 - (-3), and visa versa. 这就像你在中学学到的那样,关于4 + 3 = 4 - ( - 3),反之亦然。 At the end of the article I will explain how this is done, but I'll move onto the more important matters for now since that knowledge is not really needed for cracking or coding. 在文章的最后,我将解释这是如何完成的,但我现在将转向更重要的事项,因为破解或编码并不真正需要这些知识。

Sign and Zero Flag: 标志和零旗:

The four flags that the CMP instruction can set - Z,O,C, and S, are known as the zero, overflow, carry, and sign flags respectively. CMP指令可以设置的四个标志--Z,O,C和S分别称为零,溢出,进位和符号标志。 The zero flag is set whenever the result of the subtraction is equal to zero. 只要减法的结果等于零,就设置零标志。 This, of course, only occurs when the operands are equal. 当然,这仅在操作数相等时才会发生。 The sign flag is set when the result of the subtraction is negative. 当减法的结果为负时,设置符号标志。 Although we are inclined to think that this means the sign flag in combination with the zero flag are enough to test all > >= < and <=, this is not true, because the result can be negative even if the first number is greater than the second. 虽然我们倾向于认为这意味着符号标志与零标志组合足以测试所有>> = <和<=,但事实并非如此,因为即使第一个数字大于第二。 This is because of overflow. 这是因为溢出。

Overflow Flag: 溢出标志:

Signed integers are represented in binary with the same amount of bits as unsigned integers. 有符号整数用二进制表示,其位数与无符号整数相同。 This means, of course, that the sign must be set in one of the bits of the integer. 当然,这意味着必须在整数的一个位中设置符号。 Signed integers store the sign in the MSB (most significant bit). 有符号整数将符号存储在MSB中(最重要的位)。 This means that, while 00000001 converts to 1 in decimal, 10000001 converts to -127. 这意味着,当00000001以十进制转换为1时,10000001转换为-127。 I will discuss why it is -127 and not -1 or -2 later in the article. 我将在文章中讨论为什么它是-127而不是-1或-2。 When the processor performs subtraction, It wraps around if the subtraction goes below 00000000 or above 11111111. Therefore, if you subtract a negative number from a positive one, or subtract a positive number from a negative one, there is the possibility that the answer will overflow over the boundary. 当处理器执行减法时,如果减法低于00000000或高于11111111,它会回绕。因此,如果从正数中减去负数,或从负数中减去正数,则答案可能会溢出边界。 For example, 100 - (-100) is equal to 200, but the highest value an 8 bit signed integer can be is 127, so 200 will wrap through the upper boundary and end up as a negative number, even though it should be positive. 例如,100 - (-100)等于200,但8位有符号整数的最高值可以是127,因此200将通过上边界并最终作为负数,即使它应该是正数。 The same problem occurs with -100 - 100; -100 - 100会出现同样的问题; It wraps through the low end and ends up positive when it should be negative, causing an underflow. 当它应该为负时,它会穿过低端并最终为正,导致下溢。 Note that an underflow also sets the overflow flag, and overflow will refer to both overflows and underflows further in the article. 请注意,下溢也设置溢出标志,溢出将引用文章中的进一步溢出和下溢。 The CPU checks for this, and sets the overflow flag if it occurs. CPU检查这一点,并设置溢出标志(如果发生)。

Carry Flag: 携带旗帜:

The carry flag is set when, if both operands are interpreted as unsigned integers, the first one is greater. 如果两个操作数都被解释为无符号整数,则第一个更大时设置进位标志。 This is easy to determine because it occurs whenever the subtraction passes through 00000000 into the higher range (11111111). 这很容易确定,因为每当减法通过00000000进入更高范围(11111111)时就会发生这种情况。 For example, 00000001 - 00000010 = 11111111, so carry is set. 例如,00000001 - 00000010 = 11111111,因此设置了进位。 However, 00000010 - 00000001 = 00000001, so carry is not set. 但是,00000010 - 00000001 = 00000001,因此未设置进位。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM