这是一个简单的C程序:
void main()
{
unsigned char number1 = 4;
unsigned char number2 = 5;
if (number1 < number2)
{
number1 = 0;
}
}
所以我们在这里比较两个数字。在汇编中,它将使用cmp完成。 cmp的工作原理是从其他操作数中减去一个操作数。
现在cmp如何减去操作数?是从第二个减去第一个操作数还是反之?无论如何,这应该是这样的:
4 - 5 =(0000 0100 - 0000 0101)=(0000 0100 + 1111 1010 + 1)=(0000 0100 + 1111 1011)
= 1111 1111 = -1
因此,因为符号位= 1所以SF应该是1。
没有进位,所以CF应该是= 0.
5 - 4 =(0000 0101 - 0000 0100)=(0000 0101 + 1111 1011 + 1)
=(0000 0101 + 1111 1100)= 1 0000 0001
所以这里,CF应该是= 1
由于结果为正,因此SF应为= 0
现在我编译并运行程序(linux x86_64,gcc,gdb),在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.
(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。
因此实际结果标志(CF = 1&amp; SF = 1)不等于我们在
中计算的标志案例#1(CF = 0&amp; SF = 1)或案例#2(CF = 1&amp; SF = 0)
那是怎么回事? cmp实际上是如何设置标志的?