cmp汇编指令如何设置标志(X86_64 GNU Linux) [英] How cmp assembly instruction sets flags (X86_64 GNU Linux)
问题描述
这是一个简单的C程序:
Here is a simple C program:
void main()
{
unsigned char number1 = 4;
unsigned char number2 = 5;
if (number1 < number2)
{
number1 = 0;
}
}
所以在这里,我们正在比较两个数字.组装时将使用cmp完成. cmp的工作原理是从另一个操作数减去一个操作数.
So here we are comparing two numbers. In assembly it will be done using cmp. cmp works by subtracting one operand from other.
现在cmp如何减去操作数?它是从第二个操作数减去第一个操作数,反之亦然吗?无论如何,应该这样:
Now how cmp is subtracting operands? Is it subtracting 1st operand from 2nd or vice versa? In any case, this should go like this:
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
因此,由于符号位= 1,所以SF应该为1.
So since the sign bit = 1 so SF should be 1.
没有进位,因此CF应该= 0.
No carry, so CF should be = 0.
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
所以在这里,CF应该= 1
so here, CF should be = 1
由于结果为正,因此SF应该为0
since result is positive, SF should be = 0
现在,我编译并运行程序(Linux x86_64,gcc,gdb),在cmp指令后放置一个断点以查看寄存器状态.
Now I compile and run program (linux x86_64, gcc, gdb), place a breakpoint after cmp instruction to see register states.
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.
执行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)
所以我们可以看到在执行cmp之后,CF = 1和SF = 1.
So we can see that after cmp has been executed, both CF=1, SF=1.
因此,实际结果标志(CF = 1和SF = 1)不等于我们在
So the actual resulted flags (CF=1 & SF=1) are not equal to flags we calculated in
案例#1(CF = 0& SF = 1)或案例#2(CF = 1& SF = 0)
Case # 1 (CF=0 & SF=1) or case # 2 (CF=1 & SF=0)
那是怎么回事? cmp实际上是如何设置标志的?
Whats happening then? How cmp is actually setting the flags?
推荐答案
我想我现在明白了.这就是我的想法(设置了借款标志)
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
===
?
为此,
让我们从第一个操作数的第0位的左侧借一个1.
let's borrow a 1 from left side of bit 0 of 1st operand.
所以我们看到第一个操作数的位2是1.
so we see bit 2 of 1st operand is 1.
当位2为= 1时,表示4.
when bit 2 is = 1, it means 4.
我们知道我们可以将4写成2 +2.所以我们可以将4写成两个2.
we know that we can write 4 as 2 + 2. So we can write 4 as two 2s.
7654 3210 <-- Bit number
1
1
0000 0000
- 0000 0101
------------
因此,在上面的步骤中,我们将第一个操作数的第4位写为两个2(在第一个操作数的第2位的顶部有两个1).
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.)
再一次,我们知道,一个2可以写成两个1. 因此,我们从第一个操作数的位1借一个1,并在第一个操作数的位0上写两个1.
Now again as we know, a 2 can be written as two 1s. So we borrow one 1 from bit 1 of 1st operand and write two 1s on bit 0 of 1st operand.
7654 3210 <-- Bit number
1
11
0000 0000
- 0000 0101
------------
现在我们准备对位0和位1进行减法.
Now we are ready to perform subtraction on bit 0 and bit 1.
7654 3210 <-- Bit number
1
11
0000 0000
- 0000 0101
------------
11
因此,在解决了位0和位1之后,让我们看一下位2.
So after solving bit 0 and bit 1, lets see bit 2.
我们再次遇到相同的问题.
We again see same problem.
第一个操作数的位2 = 0
Bit 2 of 1st operand = 0
第二个操作数的位2 = 1
Bit 2 of 2nd operand = 1
要做到这一点,让我们从第一个操作数的第2位的左侧借一个1.
to do this, let's borrow a 1 from left side of bit 2 of 1st operand.
8 7654 3210 <-- Bit number
1
11
1 0000 0000
- 0000 0101
------------
11
现在您看到,第一个操作数的第8位是1.我们已经借用了这个1.
Now you see, bit 8 of 1st operand is 1. We have borrowed this 1.
在此阶段,将设置进位标志.因此CF = 1.
At this stage, carry flag will be set. So CF=1.
现在,如果位8为1,则表示256.
Now, if bit 8 is 1, it means 256.
256 = 128 + 128
256 = 128 + 128
如果第7位为1,则表示128.我们可以重写为
if bit 7 is 1, it means 128. We can rewrite as
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
请注意,对结果中的位进行签名=位7 = 1
Notice, sign bit in result = bit 7 = 1
因此将设置标志标志.即SF = 1
so sign flag will be set. i.e SF=1
因此SF = 1,CF = 1,CF = 4-5
And therefore SF=1, CF=1 after 4 - 5
这篇关于cmp汇编指令如何设置标志(X86_64 GNU Linux)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!