ADD可以设置Carry和Overflow标志吗?

时间:2018-01-10 07:10:24

标签: assembly x86 integer-overflow

我已经在装配工作了几个月。我知道进位标志和溢出标志之间的区别。

我的问题(我无法在谷歌找到答案)是否可以同时激活进位和溢出标志。我无法确定在哪里可以听到只有一个标志(或进位或溢出)可以被激活(不是同时激活)。

我们说我们有下一个代码:

xor eax, eax
xor ebx, ebx
mov al, 128
mov bl, 128
add al, bl

最后一行是否激活C和O标志? (注意al和bl具有相同的符号)

在上述情况下,我会说只会激活进位。我错了吗?

3 个答案:

答案 0 :(得分:3)

您可以将此结果推广到设置C和O的确切条件。添加中C和O的规则(至少这是一种可能的公式)

  • C =执行最高位
  • O =进入顶部位XOR执行顶部位

所以他们都可以是真的,也就是说当最后一位进位而不进入它时。

答案 1 :(得分:2)

是的,在您给出的示例中,将设置进位和溢出。

溢出标志与签名号码有关。你的例子是添加-128 + -128。结果(-256)显然不适合8位寄存器,因此设置了溢出标志。

答案 2 :(得分:1)

添加127或更少不能同时设置OF和CF(对于任何起始值)。也许你读的是在谈论添加b[4]? (请注意,1 / inc保留CF未经修改,因此这仅适用于dec

BTW,128 + 128是第一对设置两个标志的输入(对于8位操作数大小),如果使用add al, 1的嵌套循环进行搜索。我写了一个程序就是这么做的。

0..255

使用NASM或YASM在Linux(或任何操作系统,如果您在退出系统调用之前停在断点处)构建。

global _start
_start:

    mov al, 128
    add al, 128        ; set a breakpoint here and single step this, then look at flags

    xor ecx, ecx
    xor edx, edx

.edx:                       ; do {

.ecx:                       ;   do {
    movzx eax, cl           ; eax as a scratch register every iteration
                      ; writing to eax instead of al avoids a false dependency for performance.
                      ; mov eax, ecx is just as good on AMD and Haswell/Skylake, but would have partial-reg penalties on earlier Intel CPUs.
    add   al, dl
    seto  al                ; al = OF  (0 or 1)
    lahf                    ; CF is the lowest bit of FLAGS.  LAFH loads AH from the low byte of FLAGS.
    test  ah, al            ; ZF = OF & CF
    jnz   .carry_and_overflow

.continue:
    add   cl, 1             ;    add to set CF on unsigned wraparound
    jnc   .ecx              ;    } while(cl++ doesn't wrap)
    ; fall through when ECX=0

    add   dl, 1
    jnc   .edx              ; } while(dl++ doesn't wrap)

    xor   edi,edi
    mov   eax, 231
    syscall          ; exit(0) Linux 64-bit.

.carry_and_overflow:
    int3             ; run this code inside GDB.
                     ; int3 is a software breakpoint
                     ; if execution stops here, look at cl and dl
    jmp  .continue

我在gdb下使用yasm -felf64 -Worphan-labels -gdwarf2 foo.asm && ld -o foo foo.o ,然后gdb ./foo

运行此项

run我有:

~/.gdbinit

set disassembly-flavor intel layout reg set print static-members off set print pretty on macro define offsetof(t, f) &((t *) 0)->f) # https://stackoverflow.com/questions/1768620/how-do-i-show-what-fields-a-struct-has-in-gdb#comment78715348_1770422 将GDB置于文本UI全屏模式(而不是面向行)。在第一个layout reg(继续)命令(在c / rax=128)之后按住return一段时间后,然后按下control-L重绘屏幕,因为GDB的TUI内容没有工作得很好,我得到了这个:

rdx=128

一旦你停下来思考数学,模式很有趣但很容易解释:对于DL = 128,所有从128到255的CL值都设置CF和OF。但是对于更高的DL值,只有从128到CL的某些值的CL设置为两者。因为133例如表示133 - 256 = -123和┌──Register group: general──────────────────────────────────────────────────────────────────────────────────────────────────────┐ │rax 0x301 769 rbx 0x0 0 │ │rcx 0xa7 167 rdx 0x85 133 │ │rsi 0x0 0 rdi 0x0 0 │ │rbp 0x0 0x0 rsp 0x7fffffffe6c0 0x7fffffffe6c0 │ │r8 0x0 0 r9 0x0 0 │ │r10 0x0 0 r11 0x0 0 │ │r12 0x0 0 r13 0x0 0 │ │r14 0x0 0 r15 0x0 0 │ │rip 0x4000a5 0x4000a5 <_start.carry_and_overflow+1> eflags 0x202 [ IF ] │ │cs 0x33 51 ss 0x2b 43 │ │ds 0x0 0 es 0x0 0 │ │fs 0x0 0 gs 0x0 0 │ │ │ ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │0x400089 <_start.edx+5> seto al │ │0x40008c <_start.edx+8> lahf │ │0x40008d <_start.edx+9> test ah,al │ │0x40008f <_start.edx+11> jne 0x4000a4 <_start.carry_and_overflow> │ │0x400091 <_start.continue> add cl,0x1 │ │0x400094 <_start.continue+3> jae 0x400084 <_start.edx> │ │0x400096 <_start.continue+5> add dl,0x1 │ │0x400099 <_start.continue+8> jae 0x400084 <_start.edx> │ │0x40009b <_start.continue+10> xor edi,edi │ │0x40009d <_start.continue+12> mov eax,0xe7 │ │0x4000a2 <_start.continue+17> syscall │ │0x4000a4 <_start.carry_and_overflow> int3 │ >│0x4000a5 <_start.carry_and_overflow+1> jmp 0x400091 <_start.continue> │ └────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ native process 5074 In: _start.carry_and_overflow L37 PC: 0x4000a5 Program received signal SIGTRAP, Trace/breakpoint trap. _start.carry_and_overflow () at foo.asm:37 Continuing. Program received signal SIGTRAP, Trace/breakpoint trap. _start.carry_and_overflow () at foo.asm:37 Continuing. Program received signal SIGTRAP, Trace/breakpoint trap. _start.carry_and_overflow () at foo.asm:37 Continuing. Program received signal SIGTRAP, Trace/breakpoint trap. _start.carry_and_overflow () at foo.asm:37 (gdb) ,没有签名的OverFlow。非常大的无符号值表示有符号值-1或刚好低于。

另见: