简体   繁体   English

cmp汇编指令如何设置标志(X86_64 GNU Linux)

[英]How cmp assembly instruction sets flags (X86_64 GNU Linux)

Here is a simple C program: 这是一个简单的C程序:

void main()
{
       unsigned char number1 = 4;
       unsigned char number2 = 5;

       if (number1 < number2)
       {
               number1 = 0;
       }
}

So here we are comparing two numbers. 所以我们在这里比较两个数字。 In assembly it will be done using cmp. 在汇编中,它将使用cmp完成。 cmp works by subtracting one operand from other. cmp通过从其他操作数减去一个操作数来工作。

Now how cmp is subtracting operands? 现在cmp如何减去操作数? Is it subtracting 1st operand from 2nd or vice versa? 是从第二个减去第一个操作数还是反之? In any case, this should go like this: 在任何情况下,这应该是这样的:

case # 1: 情况1:

4 - 5 = (0000 0100 - 0000 0101) = (0000 0100 + 1111 1010 + 1) = (0000 0100 + 1111 1011) 4 - 5 =(0000 0100 - 0000 0101)=(0000 0100 + 1111 1010 + 1)=(0000 0100 + 1111 1011)

= 1111 1111 = -1 = 1111 1111 = -1

So since the sign bit = 1 so SF should be 1. 因此,由于符号位= 1所以SF应为1。

No carry, so CF should be = 0. 没有进位,所以CF应该= 0。

case # 2: 案例#2:

5 - 4 = (0000 0101 - 0000 0100) = (0000 0101 + 1111 1011 + 1) 5 - 4 =(0000 0101 - 0000 0100)=(0000 0101 + 1111 1011 + 1)

= (0000 0101 + 1111 1100) = 1 0000 0001 =(0000 0101 + 1111 1100)= 1 0000 0001

so here, CF should be = 1 所以在这里,CF应该是= 1

since result is positive, SF should be = 0 由于结果为正,SF应为= 0

Now I compile and run program (linux x86_64, gcc, gdb), place a breakpoint after cmp instruction to see register states. 现在我编译并运行程序(linux x86_64,gcc,gdb),在cmp指令之后放置一个断点来查看寄存器状态。

Breakpoint hit after cmp: cmp后命中断点:

Breakpoint 2, 0x0000000000400509 in main ()
(gdb) disassemble
Dump of assembler code for function main:
   0x00000000004004f6 <+0>:     push   %rbp
   0x00000000004004f7 <+1>:     mov    %rsp,%rbp
   0x00000000004004fa <+4>:     movb   $0x4,-0x2(%rbp)
   0x00000000004004fe <+8>:     movb   $0x5,-0x1(%rbp)
   0x0000000000400502 <+12>:    movzbl -0x2(%rbp),%eax
   0x0000000000400506 <+16>:    cmp    -0x1(%rbp),%al
=> 0x0000000000400509 <+19>:    jae    0x40050f <main+25>
   0x000000000040050b <+21>:    movb   $0x0,-0x2(%rbp)
   0x000000000040050f <+25>:    pop    %rbp
   0x0000000000400510 <+26>:    retq
End of assembler dump.

Register dump after cmp has been executed: 执行cmp后注册转储:

(gdb) info reg
rax            0x4  4
rbx            0x0  0
rcx            0x0  0
rdx            0x7fffffffe608   140737488348680
rsi            0x7fffffffe5f8   140737488348664
rdi            0x1  1
rbp            0x7fffffffe510   0x7fffffffe510
rsp            0x7fffffffe510   0x7fffffffe510
r8             0x7ffff7dd4dd0   140737351863760
r9             0x7ffff7de99d0   140737351948752
r10            0x833    2099
r11            0x7ffff7a2f950   140737348041040
r12            0x400400 4195328
r13            0x7fffffffe5f0   140737488348656
r14            0x0  0
r15            0x0  0
rip            0x400509 0x400509 <main+19>
eflags         0x297    [ CF PF AF SF IF ]
cs             0x33 51
ss             0x2b 43
ds             0x0  0
es             0x0  0
fs             0x0  0
gs             0x0  0
(gdb)

So we can see that after cmp has been executed, both CF=1, SF=1. 所以我们可以看到在执行cmp之后,CF = 1,SF = 1。

So the actual resulted flags (CF=1 & SF=1) are not equal to flags we calculated in 因此实际结果标志(CF = 1和SF = 1)不等于我们计算的标志

Case # 1 (CF=0 & SF=1) or case # 2 (CF=1 & SF=0) 案例#1(CF = 0&SF = 1)或案例#2(CF = 1&SF = 0)

Whats happening then? 什么事发生呢? How cmp is actually setting the flags? cmp实际上是如何设置标志的?

Operation of CMP CMP的运作
CMP performs a subtraction but does not store the result. CMP执行减法但不存储结果。
For this reason the effect on the flags is exactly the same between: 因此,对标志的影响完全相同:

cmp eax,ecx
sub eax,ecx

As per the documentation : 根据文件

Operation 手术
temp ← SRC1 − SignExtend(SRC2); temp←SRC1 - SignExtend(SRC2);
ModifyStatusFlags; ModifyStatusFlags; (* Modify status flags in the same manner as the SUB instruction*) (*以与SUB指令相同的方式修改状态标志*)
Flags Affected 受影响的旗帜
The CF, OF, SF, ZF, AF, and PF flags are set according to the result. 根据结果​​设置CF,OF,SF,ZF,AF和PF标志。

Effects on the flags 对旗帜的影响
So the following flags are affected like so: 所以以下标志会受到影响:

Assume result = op1 - op2

CF - 1 if unsigned op2 > unsigned op1
OF - 1 if sign bit of OP1 != sign bit of result
SF - 1 if MSB (aka sign bit) of result = 1
ZF - 1 if Result = 0 (i.e. op1=op2)
AF - 1 if Carry in the low nibble of result
PF - 1 if Parity of Least significant byte is even

I suggest you read up on the OF and CF here: http://teaching.idallen.com/dat2343/10f/notes/040_overflow.txt 我建议你在这里阅读OF和CF: http//teaching.idallen.com/dat2343/10f/notes/040_overflow.txt

Order of the operands 操作数的顺序
I see that you like pain and are using the braindead variant of x86 assembly called ATT-syntax. 我看到你喜欢疼痛,并且正在使用名为ATT-syntax的x86程序集的braindead变体。
This being the case you need to take into account that 在这种情况下,您需要考虑到这一点

CMP %EAX, %ECX  =>  result for the flags = ECX - EAX
CMP OP2, OP1    =   flags = OP1 - OP2

Whereas Intel syntax is 而英特尔的语法是

CMP ECX, EAX    =>  result for the flags = ECX - EAX
CMP OP1, OP2    =>  flags = OP1 - OP2

You can instruct gdb to show you Intel syntax using: set disassembly-flavor intel 您可以使用以下命令指示gdb向您显示Intel语法: set disassembly-flavor intel

I think i understand it now. 我想我现在明白了。 This is how i think it goes (borrow flag is set) 这就是我认为的方式(借旗设置)

4 - 5

1st operand = 4 = 0000 0100
2nd operand = 5 = 0000 0101

So we have to perform

      1st operand
    - 2nd operand
    --------------


      7654 3210 <-- Bit number
      0000 0100
    - 0000 0101
    ------------

Lets start.

Bit 0 of 1st operand = 0
Bit 0 of 2nd operand = 1

so

  0
- 1 
 ===
  ?

to do this, 去做这个,

let's borrow a 1 from left side of bit 0 of 1st operand. 让我们从第一个操作数的第0位左侧借一个1。

so we see bit 2 of 1st operand is 1. 所以我们看到第一个操作数的第2位是1。

when bit 2 is = 1, it means 4. 当位2 = 1时,表示4。

we know that we can write 4 as 2 + 2. So we can write 4 as two 2s. 我们知道我们可以把4写成2 + 2.所以我们可以写4作为两个2。

      7654 3210 <-- Bit number
             1
             1         
      0000 0000
    - 0000 0101
    ------------

So in above step, we have written bit 4 of 1st operand as two 2s (two 1 on top of bit 2 of 1st operand.) 所以在上面的步骤中,我们将第一个操作数的第4位写为两个2(第一个操作数的第2位顶部的两个1)。

Now again as we know, a 2 can be written as two 1s. 现在我们再次知道,2可以写成两个1。 So we borrow one 1 from bit 1 of 1st operand and write two 1s on bit 0 of 1st operand. 所以我们从第一个操作数的第1位借一个1,在第一个操作数的第0位写两个1。

      7654 3210 <-- Bit number
              1
             11         
      0000 0000
    - 0000 0101
    ------------

Now we are ready to perform subtraction on bit 0 and bit 1. 现在我们准备在第0位和第1位执行减法。

      7654 3210 <-- Bit number
              1
             11         
      0000 0000
    - 0000 0101
    ------------
             11

So after solving bit 0 and bit 1, lets see bit 2. 因此在解决了位0和位1后,让我们看看第2位。

We again see same problem. 我们再次看到同样的问题。

Bit 2 of 1st operand = 0 第1个操作数的第2位= 0

Bit 2 of 2nd operand = 1 第2个操作数的第2位= 1

to do this, let's borrow a 1 from left side of bit 2 of 1st operand. 为此,让我们从第一个操作数的第2位左侧借一个1。

    8 7654 3210 <-- Bit number
              1
             11         
    1 0000 0000
    - 0000 0101
    ------------
             11

Now you see, bit 8 of 1st operand is 1. We have borrowed this 1. 现在你看,第一个操作数的第8位是1.我们借了这个1。

At this stage, carry flag will be set. 在此阶段,将设置进位标志。 So CF=1. 所以CF = 1。

Now, if bit 8 is 1, it means 256. 现在,如果第8位为1,则表示256。

256 = 128 + 128 256 = 128 + 128

if bit 7 is 1, it means 128. We can rewrite as 如果第7位为1,则表示128.我们可以重写为

    8 7654 3210 <-- Bit number
      1       1
      1      11         
      0000 0000
    - 0000 0101
    ------------
             11

As previously, we can re-write it as: 如前所述,我们可以将其重写为:

    8 7654 3210 <-- Bit number
       1      1
      11     11         
      0000 0000
    - 0000 0101
    ------------
             11

As previously, we can re-write it as: 如前所述,我们可以将其重写为:

    8 7654 3210 <-- Bit number
        1     1
      111    11         
      0000 0000
    - 0000 0101
    ------------
             11

As previously, we can re-write it as: 如前所述,我们可以将其重写为:

    8 7654 3210 <-- Bit number
         1    1
      1111   11         
      0000 0000
    - 0000 0101
    ------------
             11

As previously, we can re-write it as: 如前所述,我们可以将其重写为:

    8 7654 3210 <-- Bit number
           1  1
      1111 1 11         
      0000 0000
    - 0000 0101
    ------------
             11

As previously, we can re-write it as: 如前所述,我们可以将其重写为:

    8 7654 3210 <-- Bit number
            1 1
      1111 1111         
      0000 0000
    - 0000 0101
    ------------
             11

At last we can solve this. 最后我们可以解决这个问题。

Subtracting 2nd operand from all above it will give 从上面的所有中减去第二个操作数将给出

    8 7654 3210 <-- Bit number
            1 1
      1111 1111         
      0000 0000
    - 0000 0101
    ------------
      1111 1111


So result = 1111 1111

Notice, sign bit in result = bit 7 = 1 注意,结果中的符号位=位7 = 1

so sign flag will be set. 所以将设置标志标志。 ie SF=1 即SF = 1

And therefore SF=1, CF=1 after 4 - 5 因此SF = 1,在4-5之后CF = 1

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

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