C语言 x86 汇编:INC 和 DEC 指令和溢出标志

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3925528/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 06:41:49  来源:igfitidea点击:

x86 Assembly: INC and DEC instruction and overflow flag

cassemblyx86x86-64inline-assembly

提问by Channel72

In x86 assembly, the overflow flag is set when an addor suboperation on a signed integer overflows, and the carry flag is set when an operation on an unsigned integer overflows.

在 x86 汇编中,溢出标志在对有符号整数的addsub运算溢出时设置,进位标志在对无符号整数的运算溢出时设置。

However, when it comes to the incand decinstructions, the situation seems to be somewhat different. According to this website, the incinstruction does not affect the carry flag at all.

然而,当谈到incdec指令时,情况似乎有些不同。根据本网站,该inc指令根本不影响进位标志。

But I can't find any information about how incand decaffect the overflow flag, if at all.

但是我找不到任何关于溢出标志的方式incdec影响的信息,如果有的话。

Do incor decset the overflow flag when an integer overflow occurs? And is this behavior the same for both signed and unsigned integers?

incdec设置溢出标志当一个整数溢出发生?对于有符号和无符号整数,这种行为是否相同?

============================= EDIT=============================

============================编辑==================== ==========

Okay, so essentially the consensus here is that INC and DEC should behave the same as ADD and SUB, in terms of setting flags, with the exception of the carry flag. This is also what it says in the Intel manual.

好的,基本上这里的共识是 INC 和 DEC 的行为应该与 ADD 和 SUB 的行为相同,就设置标志而言,进位标志除外。这也是英特尔手册中所说的。

The problem is I can't actually reproduce this behavior in practice, when it comes to unsigned integers.

问题是当涉及到无符号整数时,我实际上无法在实践中重现这种行为。

Consider the following assembly code (using GCC inline assembly to make it easier to print out results.)

考虑以下汇编代码(使用 GCC 内联汇编使打印结果更容易。)

int8_t ovf = 0;

__asm__
(
    "movb $-128, %%bh;"
    "decb %%bh;"
    "seto %b0;"
    : "=g"(ovf)
    :
    : "%bh"
);

printf("Overflow flag: %d\n", ovf);

Here we decrement a signed 8-bit value of -128. Since -128 is the smallest possible value, an overflow is inevitable. As expected, this prints out: Overflow flag: 1

在这里,我们将带符号的 8 位值递减 -128。由于 -128 是可能的最小值,因此溢出是不可避免的。正如预期的那样,这会打印出:Overflow flag: 1

But when we do the same with an unsignedvalue, the behavior isn't as I expect:

但是当我们对一个无符号值做同样的事情时,行为并不像我期望的那样:

int8_t ovf = 0;

__asm__
(
    "movb 5, %%bh;"
    "incb %%bh;"
    "seto %b0;"
    : "=g"(ovf)
    :
    : "%bh"
);

printf("Overflow flag: %d\n", ovf);

Here I increment an unsigned 8-bit value of 255. Since 255 is the largest possible value, an overflow is inevitable. However, this prints out: Overflow flag: 0.

这里我增加了一个无符号的 8 位值 255。由于 255 是可能的最大值,因此溢出是不可避免的。但是,这会打印出:Overflow flag: 0.

Huh? Why didn't it set the overflow flag in this case?

嗯?在这种情况下为什么不设置溢出标志?

回答by Ferruccio

The overflow flag is set when an operation would cause a sign change. Your code is very close. I was able to set the OF flag with the following (VC++) code:

当操作会导致符号更改时设置溢出标志。您的代码非常接近。我能够使用以下(VC++)代码设置 OF 标志:

char ovf = 0;

_asm {
    mov bh, 127
    inc bh
    seto ovf
}
cout << "ovf: " << int(ovf) << endl;

When BH is incremented the MSB changes from a 0 to a 1, causing the OF to be set.

当 BH 递增时,MSB 从 0 变为 1,从而设置 OF。

This also sets the OF:

这也设置了 OF:

char ovf = 0;

_asm {
    mov bh, 128
    dec bh
    seto ovf
}
cout << "ovf: " << int(ovf) << endl;

Keep in mind that the processor does not distinguish between signed and unsigned numbers. When you use 2's complement arithmetic, you can have one set of instructions that handle both. If you want to test for unsigned overflow, you need to use the carry flag. Since INC/DEC don't affect the carry flag, you need to use ADD/SUB for that case.

请记住,处理器不区分有符号数和无符号数。当您使用 2 的补码算法时,您可以使用一组指令来处理这两种情况。如果要测试无符号溢出,则需要使用进位标志。由于 INC/DEC 不影响进位标志,因此您需要在这种情况下使用 ADD/SUB。

回答by Channel72

Intel? 64 and IA-32 Architectures Software Developer's Manuals

英特尔?64 和 IA-32 架构软件开发人员手册

Look at the appropriate manual Instruction Set Reference, A-M. Every instruction is precisely documented.

查看相应的手册指令集参考,AM。每条指令都被精确地记录在案。

Here is the INC section on affected flags:

以下是有关受影响标志的 INC 部分:

The CF flag is not affected. The OF, SZ, ZF, AZ, and PF flags are set according to the result.

CF 标志不受影响。根据结果​​设置 OF、SZ、ZF、AZ 和 PF 标志。

回答by old_timer

try changing your test to pass in the number rather than hard code it, then have a loop that tries all 256 numbers to find the one if any that affects the flag. Or have the asm perform the loop and exit out when it hits the flag and or when it wraps around to the number it started with (start with something other than 0x00, 0x7f, 0x80, or 0xFF).

尝试更改您的测试以传递数字而不是硬编码它,然后有一个循环尝试所有 256 个数字以找到影响标志的数字(如果有的话)。或者让 asm 执行循环并在它遇到标志时退出,或者当它环绕到它开始的数字时(以 0x00、0x7f、0x80 或 0xFF 以外的其他数字开头)。

EDIT

编辑

.globl inc
inc:
    mov , %eax

top:
    inc %al
    jo done
    jmp top

done:
    ret

.globl dec
dec:
    mov , %eax

topx:
    dec %al
    jo donex
    jmp topx

donex:
    ret

Inc overflows when it goes from 0x7F to 0x80. dec overflows when it goes from 0x80 to 0x7F, I suspect the problem is in the way you are using inline assembler.

Inc 从 0x7F 变为 0x80 时溢出。当它从 0x80 到 0x7F 时 dec 溢出,我怀疑问题在于您使用内联汇编器的方式。

回答by PhiS

As many of the other answers have pointed out, INCand DECdo not affect the CF, whereas ADDand SUBdo.

正如许多其他答案所指出的那样,INC并且DEC不影响CF、whileADDSUBdo。

What has not been said yet, however, is that this might make a performance difference. Not that you'd usually be bothered by that unless you are trying to optimise the hell out of a routine, but essentially not setting the CFmeans that INC/DEConly write to part of the flags register, which can cause a partial flag register stall, see Intel 64 and IA-32 Architectures Optimization Reference Manualor Agner Fog's optimisation manuals.

然而,尚未说明的是,这可能会产生性能差异。这并不是说你通常可以通过,除非你正在设法优化地狱出常规的,但本质上不设置打扰CF意味着INC/DEC只写标志寄存器,这可能导致部分部分标志寄存器摊位,见Intel 64 and IA-32 Architectures Optimization Reference ManualAgner Fog 的优化手册

回答by Andrey

Except for the carry flag inc sets the flags the same way as add operand 1 would.

The fact that inc does not affect the carry flag is very important.

除了进位标志 inc 设置标志的方式与加操作数 1 相同。

inc 不影响进位标志这一事实非常重要。

http://oopweb.com/Assembly/Documents/ArtOfAssembly/Volume/Chapter_6/CH06-2.html#HEADING2-117

http://oopweb.com/Assembly/Documents/ArtOfAssembly/Volume/Chapter_6/CH06-2.html#HEADING2-117

回答by Olof Forshell

What the processor does is set the appropriate flags for the results of these instructions (add, adc, dec, inc, sbb, sub) for both the signed and unsigned cases i e two different flag results for every op. The alternative would be having two sets of instructions where one sets signed-related flags and the other the unsigned-related. If the issuing compiler is using unsigned variables in the operation it will test carry and zero (jc, jnc, jb, jbe etc), if signed it tests overflow, sign and zero (jo, jno, jg, jng, jl, jle etc).

处理器所做的是为有符号和无符号情况下的这些指令(add、adc、dec、inc、sbb、sub)的结果设置适当的标志,即每个操作的两个不同标志结果。另一种方法是有两组指令,其中一组设置与有符号相关的标志,另一组设置与无符号相关的标志。如果发布编译器在操作中使用无符号变量,它将测试进位和零(jc、jnc、jb、jbe 等),如果有符号则测试溢出、符号和零(jo、jno、jg、jng、jl、jle 等) )。

回答by alt.126

The CPU/ALU is only capable of handling unsigned binary numbers, and then it uses OF, CF, AF, SF, ZF, etc., to allow you to decide whether to use it as a signed number (OF), an unsigned number (CF) or a BCD number (AF).

CPU/ALU 只能处理无符号二进制数,然后它使用OF、CF、AF、SF、ZF 等,让你决定是否将其用作有符号数(OF)、无符号数(CF) 或 BCD 号码 (AF)。



About your problem, remember to consider the binary numbers themselves, as unsigned.

关于您的问题,请记住将二进制数本身视为无符号数。

**Also, the overflow and the OF require 3 numbers: The input number, a second number to use in the arithmetic, and the result number.

**此外,溢出和 OF 需要 3 个数字:输入数字、算术中使用的第二个数字和结果数字。

Overflow is activated only if the first and second numbers have the same value for the sign bit (the most significant bit) and the result has a different sign. As in, adding 2 negative numbers resulted in a positive number, or adding 2 positive numbers resulted in a negative number:

仅当第一个和第二个数字的符号位(最高有效位)的值相同并且结果具有不同的符号时,才会激活溢出。如,添加 2 个负数产生一个正数,或添加 2 个正数产生一个负数:

if( (Sign_Num1==Sign_Num2) && (Sign_Result!=Sign_Num1) ) OF=1;
else OF=0;


For your first problem, you are using -128as the first number. The second number is implicitly -1, used by the DEC instruction. So we really have the binary numbers 0x80and 0xFF. Both them have the sign bit set to 1. The result is 0x7F, which is a number with the sign bit set to 0. We got 2 initial numbers with the same sign, and a result with a different sign, so we indicate an overflow. -128-1resulted in 127, and thus the overflow flag is set to indicate a wrong signed result.

对于您的第一个问题,您使用的-128是第一个数字。第二个数字是隐式的-1,由 DEC 指令使用。所以我们真的有二进制数0x800xFF。它们都将符号位设置为 1。结果是0x7F,这是一个符号位设置为 0 的数字。我们得到 2 个具有相同符号的初始数字,以及具有不同符号的结果,因此我们表示溢出。-128-1导致127,因此设置溢出标志以指示错误的签名结果。



For your second problem, you are using 255as the first number. The second number is implicitly 1, used by the INC instruction. So we really have the binary numbers 0xFFand 0x01. Both them have a different sign bit, so it is not possible to get an overflow (it is only possible to overflow when basically adding 2 numbers of the same sign, but it is never possible to overflow with 2 numbers of a different sign because they will never lead to go beyond the possible signed value). The result is 0x00, and it doesn't set the overflow flag because 255+1, or more exactly, -1+1gives 0, which is obviously correct for signed arithmetic.

对于您的第二个问题,您使用的255是第一个数字。第二个数字是隐式的1,由 INC 指令使用。所以我们真的有二进制数0xFF0x01。它们都有不同的符号位,所以不可能得到溢出(只有在基本上将 2 个相同符号的数字相加时才有可能溢出,但永远不可能用 2 个不同符号的数字溢出,因为它们永远不会导致超出可能的有符号值)。结果是0x00,并且它没有设置溢出标志,因为255+1,或者更确切地说,-1+1给出 0,这对于有符号算术显然是正确的。

Remember that for the overflow flag to be set, the 2 numbers being added/subtracted need to have the sign bit with the same value, and then the result must have a sign bit with a value different from them.

请记住,要设置溢出标志,被加/减的 2 个数字需要具有相同值的符号位,然后结果必须具有与它们不同的值的符号位。