【发布时间】:2017-10-06 01:46:25
【问题描述】:
这是一个简单的 C 程序:
void main()
{
unsigned char number1 = 4;
unsigned char number2 = 5;
if (number1 < number2)
{
number1 = 0;
}
}
所以我们在这里比较两个数字。在汇编中,它将使用 cmp 完成。 cmp 通过从另一个操作数中减去一个操作数来工作。
现在 cmp 如何减去操作数?它是从第二个操作数中减去第一个操作数,反之亦然?无论如何,这应该是这样的:
案例#1:
4 - 5 = (0000 0100 - 0000 0101) = (0000 0100 + 1111 1010 + 1) = (0000 0100 + 1111 1011)
= 1111 1111 = -1
所以由于符号位 = 1,所以 SF 应该是 1。
没有进位,所以 CF 应该 = 0。
案例#2:
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指令后放置一个断点来查看寄存器状态。
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.
在执行 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。
所以实际产生的标志 (CF=1 & SF=1) 不等于我们在
中计算的标志案例#1(CF=0 & SF=1)或案例#2(CF=1 & SF=0)
然后呢? cmp 实际上是如何设置标志的?
【问题讨论】:
-
您误解了 CF 的值...是什么让您认为 4-5 是“无进位”? (反之亦然),这是完全错误的!
-
这个问题展示了很好的研究工作! +1
-
@Tommylee2k 是的,我做错了。感谢您指出这一点。